代码改变世界

观《编程之美》,谈读后之感

2015-03-19 16:13  微尘_无名  阅读(269)  评论(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;
}
View Code

(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;
}
View Code

(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;
}
View Code

(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;
}
View Code

 

另外,还有一篇关于”求二进制数种1的个数“的文章,用二分法做的,作者独辟蹊径,见解独到,有兴趣的读者可以前往:http://blog.csdn.net/justpub/article/details/2292823