观《编程之美》,谈读后之感
2015-03-19 16:13 微尘_无名 阅读(271) 评论(0) 编辑 收藏 举报近来观《编程之美》,收获颇多,整体上还是值得称道的,对读者思维的拓展和看问题的角度助益甚多,确能体会到编程之“美”,余观“一摞烙饼的排序”,感觉甚“爽”。但读此书过程中,发现此书略有瑕疵,虽瑕不掩瑜,还是决定在此予以指出(当然也可能是我弄错了呀):
1、本书风格不统一,建议代码全部改为伪码。
2、表述不够流畅,愿多加润色。
3、结构之法这章太简单。
4、发现书中的一些错误(打字错误就不在此指出了)和可以优化的地方,现贴在此:
(1)、在”NIM(3)两堆石头的游戏“中,代码有逻辑错误,下面是改正之后的代码(错误在注释中予以说明了):
#include <iostream> #include <vector> #include <cmath> using namespace std; bool nim(int x, int y) { if(x == y) return true; if (x > y) { swap(x, y); } if (x == 1 && y == 2) { return false; } vector<int> iv; iv.push_back(2); int delta = 1; int n = 1; int b = 2; int addition = 0; while (x > n) { while (find(iv.begin(), iv.end(), ++n) != iv.end()); ++delta; ++addition; b = n + delta; iv.push_back(b); if (iv.size() > 2 && addition >= 100) { iv.erase(remove_if(iv.begin(), iv.end(), bind2nd(less<int>(), n)), iv.end()); addition = 0; } } if ((x != n) || y != b) { //y != b 为改正之后的代码 return true; } return false; } void tester1(int x, int y) { if (nim(x, y)) { cout<<"("<<x<<", "<<y<<") Can Win"<<endl; }else{ cout<<"("<<x<<", "<<y<<") Will lose"<<endl; } } bool nim2(int x, int y) { if (x == y) { return true; } if (x > y) { swap(x, y); } double a = (1 + sqrt(5.0)) / 2; return x != (int)floor((y - x) * a); } void tester2(int x, int y) { if (nim2(x, y)) { cout<<"("<<x<<", "<<y<<") Can Win"<<endl; }else{ cout<<"("<<x<<", "<<y<<") Will lose"<<endl; } } int main(int argc, const char * argv[]) { cout<<"The Tester1:"<<endl; tester1(1, 2); tester1(3, 5); tester1(3, 6); tester1(8, 10); tester1(8, 13); tester1(50, 50); tester1(5000, 5555); cout<<"The Tester2:"<<endl; tester2(1, 2); tester2(3, 5); tester2(3, 6); tester2(8, 10); tester2(8, 13); tester2(50, 50); tester2(5000, 5555); return 0; }
(2)、在”蚂蚁爬杆“中,代码有逻辑错误,下面是改正之后的代码(错误在注释中予以说明了):
#include <iostream> using namespace std; void CalcTime(double length, double* xpos, int antNum, double speed, double& min, double& max) { double totalTime = length / speed; max = 0; min = 0; double currentMin, currentMax; for (int i = 0; i < antNum; ++i) { currentMax = 0; currentMin = 0; if (xpos[i] > (length / 2)) { currentMax = xpos[i] / speed; }else{ currentMax = (length - xpos[i]) / speed; } //这里为改正之后的代码,原书为:currentMin = totalTime - Max; currentMin = totalTime - currentMax; if (currentMax > max) { max = currentMax; } if (currentMin > min) { //这里为改正之后的代码,原书为:min < currentMin min = currentMin; } } } int main(int argc, const char * argv[]) { // insert code here... double xpos[] = {3, 7, 11, 17, 23}; double min, max; CalcTime(27, xpos, 5, 1, min, max); cout<<min<<endl; cout<<max<<endl; return 0; }
(3)、在”计算字符串的相似度“中,加入了不需要的判断(优化在注释中予以说明了):
#include <iostream> using namespace std; int inline Min(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; } int CalculateStringDistance(char *strA, int pABegin, int pAEnd, char *strB, int pBBegin, int pBEnd) { if (pABegin > pAEnd) { if (pBBegin > pBEnd) { return 0; }else{ return pBEnd - pBBegin + 1; } } if (pBBegin > pBEnd) { //以下注释部分为原书的代码,这里根本就不需要判断,与前面的判断重合了 // if (pABegin > pAEnd) { // return 0; // }else{ // return pAEnd - pABegin + 1; // } return pAEnd - pABegin + 1; } if (strA[pABegin] == strB[pBBegin]) { return CalculateStringDistance(strA, pABegin + 1, pAEnd, strB, pBBegin + 1, pBEnd); }else{ int t1 = CalculateStringDistance(strA, pABegin, pAEnd, strB, pBBegin + 1, pBEnd); int t2 = CalculateStringDistance(strA, pABegin + 1, pAEnd, strB, pBBegin, pBEnd); int t3 = CalculateStringDistance(strA, pABegin + 1, pAEnd, strB, pBBegin + 1, pBEnd); return Min(t1, Min(t2, t3)) + 1; } } #define ARRLEN(arr) sizeof(arr)/sizeof(int) int main(int argc, const char * argv[]) { // insert code here... char strA[] = "aaabcdef"; char strB[] = "abcdefgdd"; size_t lenA = strlen(strA); size_t lenB = strlen(strB); int len = CalculateStringDistance(strA, 0, lenA - 1, strB, 0, lenB - 1); cout<<len<<endl; return 0; }
(4)、在”数字哑谜和回文“中,number显然可以从10开始判断,在循环判断中加入break,可以降低接近五分之一的代码执行次数,读者可以自行实验:
#include <iostream> #include <string.h> int main(int argc, const char * argv[]) { // insert code here... bool flag; bool IsUsed[10]; int number, revert_number, t, v; for (number = 10; number < 100000; ++number) { flag = true; memset(IsUsed, 0, sizeof(IsUsed)); t = number; revert_number = 0; for (int i = 0; i < 5; ++i) { v = t % 10; revert_number = revert_number * 10 + v; t /= 10; if (IsUsed[v]) { flag = false; break; //在此处加了break,原书没有,可以减少接近五分之一的执行次数 }else{ IsUsed[v] = 1; } } if (flag && (revert_number % number == 0)) { v = revert_number / number; if (v < 10 && !IsUsed[v]) { printf("%d * %d = %d\n", number, v, revert_number); } } } return 0; }
另外,还有一篇关于”求二进制数种1的个数“的文章,用二分法做的,作者独辟蹊径,见解独到,有兴趣的读者可以前往:http://blog.csdn.net/justpub/article/details/2292823