1 1.1 第1章─概论
2
3 1.1.1 练习题
4 1. 下列关于算法的说法中正确的有( )。
5 Ⅰ.求解某一类问题的算法是唯一的
6 Ⅱ.算法必须在有限步操作之后停止
7 Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模糊
8 Ⅳ.算法执行后一定产生确定的结果
9 A. 1个 B.2个 C.3个 D.4个
10 2. T(n)表示当输入规模为n时的算法效率,以下算法效率最优的是( )。
11 A.T(n)= T(n-1)+1,T(1)=1 B.T(n)= 2n2
12 C.T(n)= T(n/2)+1,T(1)=1 D.T(n)=3nlog2n
13 3. 什么是算法?算法有哪些特征?
14 4. 判断一个大于2的正整数n是否为素数的方法有多种,给出两种算法,说明其中
15 一种算法更好的理由。
16 5. 证明以下关系成立:
17 (1)10n2-2n=(n2)
18 (2)2n+1=(2n)
19 6. 证明O(f(n))+O(g(n))=O(max{f(n),g(n)}) 。
20 7. 有一个含n(n>2)个整数的数组a,判断其中是否存在出现次数超过所有元素一
21 半的元素。
22 8. 一个字符串采用string对象存储,设计一个算法判断该字符串是否为回文。
23 9. 有一个整数序列,设计一个算法判断其中是否存在两个元素和恰好等于给定的整
24 数k。
25 10. 有两个整数序列,每个整数序列中所有元素均不相同。设计一个算法求它们的公 共元素,要求不使用STL的集合算法。
26 11. 正整数n(n>1)可以写成质数的乘积形式,称为整数的质因数分解。例如, 12=2*2*3,18=2*3*3,11=11。设计一个算法求n这样分解后各个质因数出现的次数,采 用vector向量存放结果。
27 12. 有一个整数序列,所有元素均不相同,设计一个算法求相差最小的元素对的个 数。如序列4、1、2、3的相差最小的元素对的个数是3,其元素对是(1,2),(2,3), (3,4)。
28 13. 有一个map<string,int>容器,其中已经存放了较多元素。设计一个算法求出其 中重复的value并且返回重复value的个数。
29 14. 重新做第10题,采用map容器存放最终结果。
30 15. 假设有一个含n(n>1)个元素的stack<int>栈容器st,设计一个算法出栈从栈顶
31 到栈底的第k(1≤k≤n)个元素,其他栈元素不变。
32
33 算法设计
34
35 1.1.2 练习题参考答案
36 1. 答:由于算法具有有穷性、确定性和输出性,因而Ⅱ、Ⅲ、Ⅳ正确,而解决某一
37 类问题的算法不一定是唯一的。答案为C。
38 2. 答:选项A的时间复杂度为O(n)。选项B的时间复杂度为O(n2)。选项C的时间
39 复杂度为O(log2n)。选项D的时间复杂度为O(nlog2n)。答案为C。
40 3. 答:算法是求解问题的一系列计算步骤。算法具有有限性、确定性、可行性、输
41 入性和输出性5个重要特征。
42 4. 答:两种算法如下:
43 #include
44 #include
45 bool isPrime1(int n) //方法1
46 { for (int i=2;i)
47 if (n%i==0)
48 return false;
49 return true;
50 }
51 bool isPrime2(int n) //方法2
52 { for (int i=2;i<=(int)sqrt(n);i++)
53 if (n%i==0)
54 return false;
55 return true;
56 }
57 void main()
58 { int n=5;
59 printf("%d,%d\n",isPrime1(n),isPrime2(n));
60 }
61 方法1的时间复杂度为O(n),方法2的时间复杂度为n,所以方法2更好。
62 5. 答:(1)当n足够大时,(10n2-2n)/( n2)=10,所以10n2-2n=(n2)。
63 (2)2n+1=2*2n=(2n)。
64 6. 证明:对于任意f1(n)∈O(f(n)) ,存在正常数c1和正常数n1,使得对所有n≥n1,
65 有f1(n)≤c1f(n) 。
66 类似地,对于任意g1(n)∈O(g(n)) ,存在正常数c2和自然数n2,使得对所有n≥n2,
67 有g1(n)≤c2g(n) 。
68 令c3=max{c1,c2},n3=max{n1,n2},h(n)= max{f(n),g(n)} 。
69 则对所有的n≥n3,有:
70 f1(n) +g1(n)≤c1f(n) + c2g(n)≤c3f(n)+c3g(n)=c3(f(n)+g(n))
71 ≤c32max{f(n),g(n)}=2c3h(n)=O(max{f(n),g(n)})。
72 7. 解:先将a中元素递增排序,再求出现次数最多的次数maxnum,最后判断是否满
73 足条件。对应的程序如下:
74 #include
75 #include
76 using namespace std;
77
78 2
79 第1章 概论
80
81 bool solve(int a[],int n,int &x)
82 { sort(a,a+n); //递增排序
83 int maxnum=0; //出现次数最多的次数
84 int num=1;
85 int e=a[0];
86 for (int i=1;i)
87 { if (a[i]==e)
88 { num++;
89 if (num>maxnum)
90 { maxnum=num;
91 x=e;
92 }
93 }
94 else
95 { e=a[i];
96 num=1;
97 }
98 }
99 if (maxnum>n/2)
100 return true;
101 else
102 return false;
103 }
104 void main()
105 { int a[]={2,2,2,4,5,6,2};
106 int n=sizeof(a)/sizeof(a[0]);
107 int x;
108 if (solve(a,n,x))
109 printf("出现次数超过所有元素一半的元素为%d\n",x); else
110 printf("不存在出现次数超过所有元素一半的元素\n"); }
111 上述程序的执行结果如图1.1所示。
112
113
114
115
116 图1.1 程序执行结果
117 8. 解:采用前后字符判断方法,对应的程序如下:
118 #include
119 #include <string>
120 using namespace std;
121 bool solve(string str) //判断字符串str是否为回文 { int i=0,j=str.length()-1;
122 while (i<j)
123 { if (str[i]!=str[j])
124 return false;
125
126 3
127
128 算法设计
129
130 i++; j--;
131 }
132 return true;
133 }
134 void main()
135 { cout << "求解结果" << endl;
136 string str="abcd";
137 cout << " " << str << (solve(str)?"是回文":"不是回文") << endl;
138 string str1="abba";
139 cout << " " << str1 << (solve(str1)?"是回文":"不是回文") << endl; }
140 上述程序的执行结果如图1.2所示。
141
142
143
144
145
146 图1.2 程序执行结果
147 9. 解:先将a中元素递增排序,然后从两端开始进行判断。对应的程序如下:
148 #include
149 #include
150 using namespace std;
151 bool solve(int a[],int n,int k)
152 { sort(a,a+n); //递增排序
153 int i=0, j=n-1;
154 while (i//区间中存在两个或者以上元素
155 { if (a[i]+a[j]==k)
156 return true;
157 else if (a[i]+a[j]<k)
158 i++;
159 else
160 j--;
161 }
162 return false;
163 }
164 void main()
165 { int a[]={1,2,4,5,3};
166 int n=sizeof(a)/sizeof(a[0]);
167 printf("求解结果\n");
168 int k=9,i,j;
169 if (solve(a,n,k,i,j))
170 printf(" 存在: %d+%d=%d\n",a[i],a[j],k);
171 else
172 printf(" 不存在两个元素和为%d\n",k);
173 int k1=10;
174 if (solve(a,n,k1,i,j))
175 printf(" 存在: %d+%d=%d\n",a[i],a[j],k1);
176 4
177 第1章 概论
178
179 else
180 printf(" 不存在两个元素和为%d\n",k1); }
181 上述程序的执行结果如图1.3所示。
182
183
184
185
186
187 图1.3 程序执行结果
188 10. 解:采用集合set<int>存储整数序列,集合中元素默认是递增排序的,再采用二
189 路归并算法求它们的交集。对应的程序如下:
190 #include
191 #include <set>
192 using namespace std;
193 void solve(set<int> s1,set<int> s2,set<int> &s3) //求交集s3
194 { set<int>::iterator it1,it2;
195 it1=s1.begin(); it2=s2.begin();
196 while (it1!=s1.end() && it2!=s2.end())
197 { if (*it1==*it2)
198 { s3.insert(*it1);
199 ++it1; ++it2;
200 }
201 else if (*it1<*it2)
202 ++it1;
203 else
204 ++it2;
205 }
206 }
207 void dispset(set<int> s) //输出集合的元素
208 { set<int>::iterator it;
209 for (it=s.begin();it!=s.end();++it)
210 printf("%d ",*it);
211 printf("\n");
212 }
213 void main()
214 { int a[]={3,2,4,8};
215 int n=sizeof(a)/sizeof(a[0]);
216 set<int> s1(a,a+n);
217 int b[]={1,2,4,5,3};
218 int m=sizeof(b)/sizeof(b[0]);
219 set<int> s2(b,b+m);
220 set<int> s3;
221 solve(s1,s2,s3);
222 printf("求解结果\n");
223 printf(" s1: "); dispset(s1);
224
225 5
226
227
228 printf(" s2: "); dispset(s2); printf(" s3: "); dispset(s3); }
229 上述程序的执行结果如图1.4所示。
230
231
232 算法设计
233
234
235
236
237
238
239 图1.4 程序执行结果
240 11. 解:对于正整数n,从i=2开始查找其质因数,ic记录质因数i出现的次数,当找
241 到这样质因数后,将(i,ic)作为一个元素插入到vector容器v中。最后输出v。对应的 算法如下:
242 #include
243 #include
244 using namespace std;
245 struct NodeType //vector向量元素类型
246 { int p; //质因数
247 int pc; //质因数出现次数
248 };
249 void solve(int n,vector &v) //求n的质因数分解
250 { int i=2;
251 int ic=0;
252 NodeType e;
253 do
254 { if (n%i==0)
255 { ic++;
256 n=n/i;
257 }
258 else
259 { if (ic>0)
260 { e.p=i;
261 e.pc=ic;
262 v.push_back(e);
263 }
264 ic=0;
265 i++;
266 }
267 } while (n>1 || ic!=0);
268 }
269 void disp(vector &v) //输出v
270 { vector::iterator it;
271 for (it=v.begin();it!=v.end();++it)
272 printf(" 质因数%d出现%d次\n",it->p,it->pc);
273 }
274
275 6
276
277
278 void main()
279 { vector v;
280 int n=100;
281 printf("n=%d\n",n);
282 solve(n,v);
283 disp(v);
284 }
285 上述程序的执行结果如图1.5所示。
286
287 第1章 概论
288
289
290
291
292
293 图1.5 程序执行结果
294 12. 解:先递增排序,再求相邻元素差,比较求最小元素差,累计最小元素差的个
295 数。对应的程序如下:
296 #include
297 #include
298 #include
299 using namespace std;
300 int solve(vector<int> &myv) //求myv中相差最小的元素对的个数
301 { sort(myv.begin(),myv.end()); //递增排序
302 int ans=1;
303 int mindif=myv[1]-myv[0];
304 for (int i=2;i)
305 { if (myv[i]-myv[i-1]<mindif)
306 { ans=1;
307 mindif=myv[i]-myv[i-1];
308 }
309 else if (myv[i]-myv[i-1]==mindif)
310 ans++;
311 }
312 return ans;
313 }
314 void main()
315 { int a[]={4,1,2,3};
316 int n=sizeof(a)/sizeof(a[0]);
317 vector<int> myv(a,a+n);
318 cout << "相差最小的元素对的个数: " << solve(myv) << endl;
319 }
320 上述程序的执行结果如图1.6所示。
321
322
323
324
325
326 7
327
328 算法设计
329
330 图1.6 程序执行结果
331 13. 解:对于map<string,int>容器mymap,设计另外一个map<int,int>容器tmap,
332 将前者的value作为后者的关键字。遍历mymap,累计tmap中相同关键字的次数。一个 参考程序及其输出结果如下:
333 #include
334 #include