C++程序设计教程(钱能)第六章 学习笔记
1. 频繁调用一个小函数
#include <iostream>
using namespace std;
bool isNumber(char);
bool isNumber(char ch) {
return ch >= '0'&& ch <= '9' ? 1:0;
}
int main(int argc, char** argv) {
char c;
while (cin >> c&&c != '\n') {
if (isNumber(c))
cout << "You entered a digit.\n";
else
cout << "You entered a non-digit.\n";
}
}
/*运行结果:
10a-gnb7=2d789
You entered a digit.
You entered a digit.
You entered a non-digit.
You entered a non-digit.
You entered a non-digit.
You entered a non-digit.
You entered a non-digit.
You entered a digit.
You entered a non-digit.
You entered a digit.
You entered a non-digit.
You entered a digit.
You entered a digit.
You entered a digit.
*/
2. 将小函数“融化”在调用处
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
char c;
while (cin >> c&&c != '\n') {
if (c >= '0'&& c <= '9')
cout << "You entered a digit.\n";
else
cout << "You entered a non-digit.\n";
}
}
3. 内联函数
#include <iostream>
using namespace std;
inline bool isNumber(char);//内联声明
bool isNumber(char ch) {
return ch >= '0'&& ch <= '9' ? 1:0;
}
int main(int argc, char** argv) {
char c;
while (cin >> c&&c != '\n') {
if (isNumber(c))
cout << "You entered a digit.\n";
else
cout << "You entered a non-digit.\n";
}
}
4. 未声明内联
#include <iostream>
using namespace std;
bool isNumber(char); //此处无inline
inline bool isNumber(char ch) {//此处为inline
return ch >= '0'&& ch <= '9' ? 1:0;
}
int main(int argc, char** argv) {
char c;
while (cin >> c&&c != '\n') {
if (isNumber(c))
cout << "You entered a digit.\n";
else
cout << "You entered a non-digit.\n";
}
}
5. 内联性能测试
#include <iostream>
#include <time.h>
using namespace std;
int calc1(int a, int b) {
return a + b;
}
inline int calc2(int a, int b) {
return a + b;
}
int main(int argc, char** argv) {
int x[1000], y[1000], z[1000];
clock_t t = clock();
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
for (int k = 0; k < 1000; k++) {
z[i] = calc1(x[j], y[k]);
}
}
}
cout << "Not using inline:" << (clock() - t) / CLK_TCK << " seconds\n";
t = clock();
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
for (int k = 0; k < 1000; k++) {
z[i] = calc2(x[j], y[k]);
}
}
}
cout << "Using inline:" << (clock() - t) / CLK_TCK << " seconds\n";
}
/*运行结果:
Not using inline:18 seconds
Using inline:17 seconds
*/
6. 安排车厢顺序栈版本
//rail.txt
5
3 2 1 5 4
5 4 1 2 3
0
6
6 5 4 3 2 1
0
0
#include <fstream>
#include<sstream>
#include<stack>
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
ifstream in("rail.txt");//尤其注意每行最后一个数字不要多敲空格,否则会影响结果。如:“5”敲成“5 ”
for (int n, line = 0; in>>n && n && in.ignore(); ) {//读入每组数据的n,表示由n节车厢组成。in.ignore()表示忽略文件在读去整数后的回车
cout << (line++ ? "\n" : "");//控制输出"\n",第一组数据不用换行,剩余各组数据之间都要以空行分隔
for (string s; getline(in, s) && s != "0"; ) {//读入该组数据的每种车厢顺序
istringstream sin(s);//将每种车厢顺序作为输入string流的初始值
stack<int>st;//定义栈
for (int last = 0, coach; sin >> coach; st.pop()) {
//依次读某顺序的一个元素到coach中,last是最后读入的车厢号信息
for (int p = last + 1; p <= coach; ++p) {//将该车厢号进栈
st.push(p);
}
if (last < coach)last = coach;//记录最后读入的车厢号信息
if (st.top() != coach)break;//判断栈顶元素是否是当前车厢
}
cout << (!sin ? "Yes\n" : "No\n");
//判断string流中的数据是否已读完,若读完,则说明所有的车厢号能对应起来,输出Yes,否则输出No。
}
}
}
/*运行结果:
Yes
No
Yes
*/
7. 安排车厢顺序向量版
//rail.txt
5
3 2 1 5 4
5 4 1 2 3
0
6
6 5 4 3 2 1
0
0
#include <fstream>
#include<sstream>
#include<vector>
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
ifstream in("rail.txt");//尤其注意每行最后一个数字不要多敲空格,否则会影响结果。如:“5”敲成“5 ”
for (int n, line = 0; in>>n && n && in.ignore(); ) {//读入每组数据的n,表示由n节车厢组成。in.ignore()表示忽略文件在读去整数后的回车
cout << (line++ ? "\n" : "");//控制输出"\n",第一组数据不用换行,剩余各组数据之间都要以空行分隔
for (string s; getline(in, s) && s != "0"; ) {//读入该组数据的每种车厢顺序
istringstream sin(s);//将每种车厢顺序作为输入string流的初始值
vector<int>st;//定义栈
for (int last = 0, coach; sin >> coach; st.erase(st.begin())) {
//依次读某顺序的一个元素到coach中,last是最后读入的车厢号信息
for (int p = last + 1; p <= coach; ++p) {//将该车厢号进栈
st.insert(st.begin(),p);
}
if (last < coach)last = coach;//记录最后读入的车厢号信息
if (st.front() != coach)break;//判断栈顶元素是否是当前车厢
}
cout << (!sin ? "Yes\n" : "No\n");
//判断string流中的数据是否已读完,若读完,则说明所有的车厢号能对应起来,输出Yes,否则输出No。
}
}
}
/*运行结果:
Yes
No
Yes
*/
改进
若以向量尾来做栈顶,充分利用向量“延伸”性能,程序效率会十分接近stack容器。修改以下三处即可:
for (int last = 0, coach; sin >> coach; st.pop_back()) {//修改
for (int p = last + 1; p <= coach; ++p) {
st.push_back(p);//修改
}
if (last < coach)last = coach;
if (st.back() != coach)break;//修改
}
8. Fibonacci数列四种方法比较
#include<vector>
#include<cmath>
#include <iostream>
#include <time.h>
using namespace std;
int fibo1(int n) {
if (n < 2)
return n;
else
return fibo1(n - 1) + fibo1(n - 2);
}
int fibo2(int n) {
int a = 0, c;
for (int b = 1,i = 2; i <= n; ++i) {
c = a + b;
a = b;
b = c;
}
return c;
}
int fibo3(int n) {
vector<int>v(n + 1, 0);
v[1] = 1;
for (int i = 2; i <= n; ++i) {
v[i] = v[i - 1] + v[i - 2];
}
return v[n];
}
int fibo4(int n) {
return (pow((1 + sqrt(5.0)) / 2, n) - pow((1 - sqrt(5.0)) / 2, n)) / sqrt(5.0);
}
int main(int argc, char** argv) {
int a;
clock_t start = clock();
for (int i = 1; i < 5; ++i)
a = fibo1(35);
cout << "Fibo1's time was:" << (clock() - start) / (double)CLK_TCK << endl;
start = clock();
for (int i = 1; i < 5; ++i)
a = fibo2(35);
cout << "Fibo2's time was:" << (clock() - start) / (double)CLK_TCK << endl;
start = clock();
for (int i = 1; i < 5; ++i)
a = fibo3(35);
cout << "Fibo3's time was:" << (clock() - start) / (double)CLK_TCK << endl;
start = clock();
for (int i = 1; i < 5; ++i)
a = fibo4(35);
cout << "Fibo4's time was:" << (clock() - start) / (double)CLK_TCK << endl;
}
//运行结果:
// Fibo1's time was:2.504
// Fibo2's time was:0
// Fibo3's time was:0
// Fibo4's time was:0
//
#include<vector>
#include<cmath>
#include <iostream>
#include <time.h>
using namespace std;
int fibo1(int n) {
if (n < 2)
return n;
else
return fibo1(n - 1) + fibo1(n - 2);
}
int fibo2(int n) {
int a = 0, c;
for (int b = 1,i = 2; i <= n; ++i) {
c = a + b;
a = b;
b = c;
}
return c;
}
int fibo3(int n) {
vector<int>v(n + 1, 0);
v[1] = 1;
for (int i = 2; i <= n; ++i) {
v[i] = v[i - 1] + v[i - 2];
}
return v[n];
}
int fibo4(int n) {
return (pow((1 + sqrt(5.0)) / 2, n) - pow((1 - sqrt(5.0)) / 2, n)) / sqrt(5.0);
}
int main(int argc, char** argv) {
int a;
clock_t start = clock();
for (int i = 0; i < 1000000; ++i)
a = fibo2(45);
cout << "Fibo2's time was:"<< (clock() - start) / (double)CLK_TCK << endl;
start = clock();
for (int i = 0; i < 1000000; ++i)
a = fibo3(45);
cout << "Fibo3's time was:" << (clock() - start) / (double)CLK_TCK << endl;
start = clock();
for (int i = 0; i < 1000000; ++i)
a = fibo4(45);
cout << "Fibo4's time was:" << (clock() - start) / (double)CLK_TCK << endl;
}
/*运行结果:
n=15时:
Fibo2's time was:0.077
Fibo3's time was:16.196
Fibo4's time was:0.221
n=30时:
Fibo2's time was:0.148
Fibo3's time was:26.362
Fibo4's time was:0.219
n=45时:
Fibo2's time was:0.21
Fibo3's time was:37.76
Fibo4's time was:0.22
*/
9. Fibonacci数列两种方法比较
测试文件 data.txt 与 data_30000.txt 的生成见文章:
C++ 生成指定范围内的10000个数据
#include <fstream>
#include<vector>
#include <iostream>
#include <time.h>
using namespace std;
int main(int argc, char** argv) {
ifstream in("data_30000.txt");
ofstream out3("out3.txt");
ofstream out4("out4.txt");
clock_t start = clock();
for (int n; in >> n&&n; ) {
int a = 0, c = 0;
for (int b = 1, i = 2; i <= n ; ++i) {
c = a + b;
a = b;
b = c;
}
out3 << c << " ";
}
cout << "Fibo2 'time was: " << (clock() - start) / double(CLK_TCK) << endl;
//(类型)(变量/表达式)是C语言形式 类型(变量/表达式)是C++形式
ifstream in1("data_30000.txt");
start = clock();
vector<int>v(47, 1);
for (int i = 3; i < 47; ++i)
v[i] = v[i - 1] + v[i - 2];
for (int n; in1 >> n&&n; )
out4 << v[n] << " ";
cout<< "Fibo3 'time was: " << (clock() - start) / double(CLK_TCK) << endl;
}
/*运行结果:
文件中含有10000个数据时:
Fibo2 'time was: 0.101
Fibo3 'time was: 0.109
文件中含有30000个数据时:
Fibo2 'time was: 0.279
Fibo3 'time was: 0.265
*/
10. 矩形积分
//integral.txt
3
27.64738
0.0493
0.99954
0.0000557
100001
#include <fstream>
#include<cmath>
#include<iomanip>
#include <iostream>
using namespace std;
double g(double x) {//被积函数
return 1 / x;
}
double rectangle(double a, double b, double(*f)(double)) {//f为函数指针
double w = b - a;//区间长度
double sumNew = w*(f(a) + f(b)) / 2;//n=1时的积分值,即梯形面积=(上底+下底)*高*1/2
double sumOld = 0;//旧的积分值
for (int n = 1; abs(sumNew - sumOld) >= 1e-4; n *= 2) {//精度为10的-4次幂,n是划分的矩形数
sumOld = sumNew;//将新的积分值赋给旧的积分值
sumNew = 0;//为计算新的积分值做准备
for (int i = 0; i < n; ++i)
sumNew += f(a + w*(i + 0.5) / n);//计算n个小矩形的高之和:sumNew = f(a+w/n(0+0.5))+f(a+w/n(1+0.5))+...
sumNew *= w / n;//乘每个矩形的宽就是新的积分值
}
return sumNew;//返回新的积分值
}
int main(int argc, char** argv) {
ifstream in("integral.txt");
cout << setprecision(3) << fixed;//保留小数点后三位
for (double b; in >> b; )
cout << rectangle(1, b, g) << endl;
}
/*运行结果:
1.099
3.320
-3.010
-0.000
-9.796
11.513
*/
11. 梯形积分
//integral.txt
3
27.64738
0.0493
0.99954
0.0000557
100001
#include <fstream>
#include<cmath>
#include<iomanip>
#include <iostream>
using namespace std;
double g(double x) {//被积函数
return 1 / x;
}
double trapezoid(double a, double b, double(*f)(double)) {//f为函数指针
double h = b - a;//梯形的高
double T2n = h*(f(a) + f(b)) / 2;//n=1时的积分值,即梯形面积=(上底+下底)*高*1/2
double Tn = 0;
int n;
for (n = 1; abs(T2n - Tn) > 1e-3; n += n, h /= 2.0) {//精度为10的-3次幂,n是划分的梯形数
Tn = T2n;
double sigma = 0;
for (int k = 0; k < n; k++)
sigma += f(a + (k + 0.5)*h);//各个梯形的中位线之和
T2n = (Tn + h*sigma) / 2;//变步长梯形公式计算面积的近似值
}
cout << "n = " << n << ", ";
return T2n;
}
int main(int argc, char** argv) {
ifstream in("integral.txt");
cout << fixed << setprecision(3);//保留小数点后三位
for (double b; in >> b; )
cout << trapezoid(1, b, g) << endl;
}
/*运行结果:
n = 32, 1.099
n = 512, 3.320
n = 512, -3.010
n = 1, -0.000
n = 524288, -9.796
n = 2097152, 11.513
*/
12. 辛普生积分
//integral.txt
3
27.64738
0.0493
0.99954
0.0000557
100001
#include <fstream>
#include<cmath>
#include<iomanip>
#include <iostream>
using namespace std;
double g(double x) {//被积函数
return 1 / x;
}
double simpson(double a, double b, double(*f)(double)) {//f为函数指针
double I2n = 0;
double h = b - a;//梯形的高
double T2n = h*(f(a) + f(b)) / 2;//n=1时的积分值,即梯形面积=(上底+下底)*高*1/2
double In = T2n,Tn;
for (int n = 1; abs(I2n - In) > 1e-3; n += n, h /= 2.0) {//精度为10的-3次幂,n是划分的梯形数
In = I2n;
Tn = T2n;
double sigma = 0;
for (int k = 0; k < n; k++)
sigma += f(a + (k + 0.5)*h);//各个梯形的中位线之和
T2n = (Tn + h*sigma) / 2;//变步长梯形公式计算面积的近似值
I2n = (4 * T2n - Tn) / 3;//变步长辛普生公式计算面积的近似值
}
return I2n;
}
int main(int argc, char** argv) {
ifstream in("integral.txt");
cout << fixed << setprecision(3);//保留小数点后三位
for (double b; in >> b; )
cout << simpson(1, b, g) << endl;
}
/*运行结果:
1.099
3.320
-3.010
0.000(矩形法求得-0.000)
-9.796
11.513
*/
三种算法的比较
13. 判断字串相等
【方法1】
//string.txt
010101
11100
110011001100
000011110011
#include <fstream>
#include<sstream>
#include <iostream>
#include<algorithm>
using namespace std;
int main(int argc, char** argv) {
ifstream in("string.txt");
for (string s, t; in >> s >> t; ) {
sort(s.begin(), s.end());
sort(t.begin(), t.end());
cout << ( s == t ? "Yes" : "No") << endl;
}
}
/*运行结果:
No
Yes
*/
【方法2】
#include <fstream>
#include<sstream>
#include <iostream>
#include<algorithm>
using namespace std;
int main(int argc, char** argv) {
ifstream in("string.txt");
for (string s, t; in >> s >> t; ) {
int sc1 = count(s.begin(), s.end(), '1');
int sc0 = count(s.begin(), s.end(), '0');
int tc1 = count(t.begin(), t.end(), '1');
int tc0 = count(t.begin(), t.end(), '0');
cout << (sc1 == tc1 && sc0 == tc0 ? "Yes" : "No") << endl;
}
}
/*运行结果:
No
Yes
*/
【方法3】
#include <fstream>
#include<sstream>
#include <iostream>
#include<algorithm>
using namespace std;
int main(int argc, char** argv) {
ifstream in("string.txt");
for (string s, t; in >> s >> t; ) {
int sc1 = count(s.begin(), s.end(), '1');
int tc1 = count(t.begin(), t.end(), '1');
cout << (sc1 == tc1 && s.length()==t.length() ? "Yes" : "No") << endl;
}
}
/*运行结果:
No
Yes
*/
【方法4】
#include<stdio.h>
#include<string.h>
#include <iostream>
using namespace std;
int cnt(char *a) {
int num = 0;
while (*a){
if (*a++ == '1')
num++;
}
return num;
}
int main(int argc, char** argv) {
FILE* iFile = fopen("string.txt", "rt");
while (1) {
char a[1025], b[1025];
fscanf(iFile, "%s", a);
fscanf(iFile, "%s", b);
printf("%s", strlen(a) == strlen(b) && cnt(a) == cnt(b) ? "Yes\n" : "No\n");
if (feof(iFile))
break;
}
fclose(iFile);
}
/*运行结果:
No
Yes
*/
14. 剩余串排列
//remainder.txt
computer program
Write program
thatwill askthe
user fora
whole number
【方法1】
#include <fstream>
#include<sstream>
#include <iterator>
#include <iostream>
#include<algorithm>
using namespace std;
int main(int argc, char** argv) {
string s;
cout << (s=="") << endl;//1 说明未经初始化的字符串是空串
ifstream in("remainder.txt");
for (string s, t, u; in >> s >> t; u = "") {
sort(s.begin(), s.end());
sort(t.begin(), t.end());
set_difference(s.begin(), s.end(), t.begin(), t.end(), back_inserter(u));
cout << u << endl;
}
}
/*运行结果:
cetu
Weit
illtw
esu
hlow
*/
【方法2】
#include <fstream>
#include<sstream>
#include<algorithm>
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
ifstream in("remainder.txt");
for (string s, t; in >> s >> t; ) {
sort(s.begin(), s.end());
for (int i = 0; i < s.length(); ++i) {
if (t.find(s[i]) == string::npos)
cout << s[i];
}
cout << endl;
}
}
/*运行结果:
cetu
Weit
illw(与方法1中的illtw不同)
esu
hlow
*/
15. 清点单词数
// xyz.txt
4Factually waste separation is
3vital to create
2environment-friendly campus.
1Firstly,
5waste separation does great contribution
7to the environmental protection. Since some of
6waste is recyclable, while other is
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <iostream>
using namespace std;
typedef multimap<int, int>Mmap;
int main(int argc, char** argv) {
ifstream in("xyz.txt");
vector<string>abc;
//abc.reserve(1100);
Mmap nums;
int n = 0;
for (string s; getline(in, s); ) {
istringstream sin(s);
int num = 0;
for (string t; sin >> t; num++);
if (num) {
nums.insert(Mmap::value_type(num, n++));
abc.push_back(s);
}
}
for (Mmap::iterator it = nums.begin(); it != nums.end(); ++it)
cout << abc[it->second] << endl;
}
/*运行结果:
1Firstly,
2environment-friendly campus.
3vital to create
4Factually waste separation is
5waste separation does great contribution
6waste is recyclable, while other is
7to the environmental protection. Since some of
*/
16. 求素数个数
【方法1】
#include<cmath>
#include <iostream>
using namespace std;
bool isPrime(int n) {
int sqrtn = sqrt(n*1.0);
for (int i = 2; i <= sqrtn; ++i)
if (n%i == 0)
return false;
return true;
}
int main(int argc, char** argv) {
int num = 0;
for (int i = 2; i <= 100000000; i++) {
if (isPrime(i))
num++;
}
cout << "num = " << num << endl;//num = 5761455
}
【方法2】
#include<bitset>
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
bitset<100000000>*p = new bitset<100000000>;
p->set();
for(int i = 2; i <= 10000; ++i) {
if (p->test(i)) {
for (int j = i*i; j < p->size(); j += i)
p->reset(j);
}
}
int num = 0;
for (int i = 2; i < 100000000; ++i) {
if (p->test(i))
num++;
}
cout << "num = " << num << endl;//num = 5761455
delete[]p;
}
17. 求素数个数低级编程版
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <iostream>
using namespace std;
int count(unsigned int a) {
int sum = 0;
for (unsigned int x = a; x; x >>= 1) {
if (x & 1)
sum++;
}
return sum;
}
void sieve(unsigned int * p) {
for (int i = 2; i <= 10000; ++i) {
if (p[i / 32] & (1 << i % 32)) {
for (int j = i*i; j < 100000000; j += i)
p[j / 32] &= ~(1 << j % 32);
}
}
}
int main(int argc, char** argv) {
clock_t start = clock();
unsigned int*p = (unsigned int*)malloc(12500000);
if (!p) {
printf("No enough memory!\n");
return 1;
}
memset(p, 255, 12500000);
sieve(p);
int num = -2;//因为初始化都为1,而0和1不是素数,最后素数总数要减2
for (int i = 0; i < 12500000 / 4; ++i)
num += count(p[i]);
free(p);
printf("素数个数:%d\n计算耗时:%7.3f\n", num, (clock() - start) / double(CLK_TCK));
}
/*运行结果:
素数个数:5761455
计算耗时: 1.715
*/
18. 求素数个数,比较不同方法
#include<bitset>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <iostream>
using namespace std;
int sieveSTL();
int sieve();
int sieveSTL() {
bitset<100000000>& p = *new bitset<100000000>;
p.set();
int num = 100000000 - 2;
for (int i = 2; i <= 10000; ++i) {
if (p.test(i)) {
for (int j = i * i; j < p.size(); j += i) {
if (p.test(j) && num--)
p.reset(j);
}
}
}
delete[] & p;
return num;
}
int sieve() {
unsigned int * p = (unsigned int *)malloc(12500000);
memset(p, 255, 12500000);
int num = 100000000 - 2;
for (int i = 2; i <= 10000; i++) {
if (p[i / 32] & (1 << i % 32)) {
for (int j = i * i; j < 100000000; j += i) {
if (p[j / 32] & (1 << j % 32) && num--) {
p[j / 32] &= ~(1 << j % 32);
}
}
}
}
free(p);
return num;
}
int main(int argc, char** argv) {
clock_t start = clock();
cout << "低级筛法:" << sieve();
cout << "\t" << (clock() - start) / double(CLK_TCK) << "sec\n";
start = clock();
cout << "STL容器 :" << sieveSTL();
cout << "\t" << (clock() - start) / double(CLK_TCK) << "sec\n";
}
/*运行结果:
低级筛法:5761455 1.648sec
STL容器 :5761455 23.117sec
*/