1 1.1 第 1 章─概论
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. 证明以下关系成立:
13 (1)10n2-2n=(n2)
14 (2)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*3,18=2*3*3,11=11。设计一个算法求 n 这样分解后各个质因数出现的次数,采用 vector 向量存放结果。
21 12. 有一个整数序列,所有元素均不相同,设计一个算法求相差最小的元素对的个数。如序列 4、1、2、3 的相差最小的元素对的个数是 3,其元素对是(1,2),(2,3),
22 (3,4)。
23 13. 有一个 map<string,int>容器,其中已经存放了较多元素。设计一个算法求出其中重复的 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 #include
34 bool isPrime1(int n) //方法 1
35 { for (int i=2;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)。
52 (2)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 #include 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)
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 所示。
96 图 1.1 程序执行结果
97 8. 解:采用前后字符判断方法,对应的程序如下:
98 #include #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 所示。
118 图 1.2 程序执行结果
119 9. 解:先将 a 中元素递增排序,然后从两端开始进行判断。对应的程序如下:
120 #include #include 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//区间中存在两个或者以上元素
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 所示。
151 图 1.3 程序执行结果
152 10. 解:采用集合 set<int>存储整数序列,集合中元素默认是递增排序的,再采用二路归并算法求它们的交集。对应的程序如下:
153 #include #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 所示。
192 图 1.4 程序执行结果
193 11. 解:对于正整数 n,从 i=2 开始查找其质因数,ic 记录质因数 i 出现的次数,当找到这样质因数后,将(i,ic)作为一个元素插入到 vector 容器 v 中。最后输出 v。对应的算法如下:
194 #include #include using namespace std;
195 struct NodeType //vector 向量元素类型
196 { int p; //质因数
197 int pc; //质因数出现次数
198 };
199 void solve(int n,vector &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 &v) //输出 v
220 { vector::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 v;
227 int n=100;
228 printf("n=%d\n",n);
229 solve(n,v);
230 disp(v);
231 }
232 上述程序的执行结果如图 1.5 所示。
233 图 1.5 程序执行结果
234 12. 解:先递增排序,再求相邻元素差,比较求最小元素差,累计最小元素差的个数。对应的程序如下:
235 #include #include #include 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)
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
259 图 1.6 程序执行结果
260 13. 解:对于 map<string,int>容器 mymap,设计另外一个 map<int,int>容器 tmap, 将前者的 value 作为后者的关键字。遍历 mymap,累计 tmap 中相同关键字的次数。一个参考程序及其输出结果如下:
261 #include #include