Coursera 斯坦福 算法課 Course 1 Week 1

本節課主要講了大O ,大Θ ,小o 的概念。
然後講了時間複雜度的分析方法,以及分治法。作業題是:
使用karatsuba算法計算大數乘法:
So: what’s the product of the following two 64-digit numbers?
3141592653589793238462643383279502884197169399375105820974944592
2718281828459045235360287471352662497757247093699959574966967627
這兩個數應該是pi和e的64位。
小學學的計算的乘法複雜度是Θ(n2) ,而karatsuba的時間複雜度是Θ(nlog2(3))

代碼如下:

#include <iostream>
#include <ostream>
#include <istream>
#include <cstring>
using namespace std;


class uint128_base10_t {
public:
    enum class HALF { HIGH, LOW };
    static const int LENGTH = 128;
    uint128_base10_t();
    uint128_base10_t(const string &str);
    ~uint128_base10_t();
    uint128_base10_t(const uint128_base10_t & d);
    uint128_base10_t & operator = (const uint128_base10_t & d);
    friend uint128_base10_t operator + (const uint128_base10_t &left, const uint128_base10_t &right);
    friend uint128_base10_t operator - (const uint128_base10_t &left, const uint128_base10_t &right);
    friend uint128_base10_t operator * (const uint128_base10_t &left, const uint128_base10_t &right);
    friend uint128_base10_t operator << (uint128_base10_t &left, int i);
    friend ostream& operator << (ostream &in, const uint128_base10_t &data);

    friend bool operator < (const uint128_base10_t &left, const uint128_base10_t &right);

    uint128_base10_t halfSplit(HALF h) const;
    size_t getDataLength() const { return _length; };
    inline const uint8_t *getData() const { return _data; };
private:
    uint8_t *_data;
    int _length;
    size_t calcDataLength() const;
};

int main()
{
    uint128_base10_t a(string("3141592653589793238462643383279502884197169399375105820974944592"));
    uint128_base10_t b(string("2718281828459045235360287471352662497757247093699959574966967627"));
    uint128_base10_t c = a*b;

    cout << c << endl;
    return 0;
}



uint128_base10_t::uint128_base10_t() {
    _data = new uint8_t[LENGTH];
    memset(_data, 0, LENGTH);
    _length = 0;
}

uint128_base10_t::uint128_base10_t(const string &str) {
    _data = new uint8_t[LENGTH];
    memset(_data, 0, LENGTH);
    size_t strLen = str.length();
    for (int i(strLen-1); i >= 0; i--)
    {
        _data[i] = str[strLen - i - 1] - 0x30;
    }
    _length = strLen;

}

uint128_base10_t::~uint128_base10_t() {
    delete[] _data;
    _data = nullptr;
}

uint128_base10_t& uint128_base10_t::operator=(const uint128_base10_t &d) {
    memset(_data, 0, LENGTH);
    memcpy(_data, d.getData(), LENGTH);
    _length = d.getDataLength();
    return *this;
}

uint128_base10_t::uint128_base10_t(const uint128_base10_t &d) {
    _data = new uint8_t[LENGTH];
    memset(_data, 0, LENGTH);
    memcpy(_data, d.getData(), LENGTH);
    _length = d.getDataLength();
}

uint128_base10_t operator + (const uint128_base10_t &left, const uint128_base10_t &right) {
    uint8_t carry(0);
    uint128_base10_t result;

    const uint8_t* leftData = left.getData();
    const uint8_t* rightData = right.getData();
    uint8_t* resultData = result._data;

    for (int i(0); i < uint128_base10_t::LENGTH; i++) {
        resultData[i] = leftData[i] + rightData[i] + carry;
        carry = resultData[i] / 10;
        resultData[i] = resultData[i] % 10;
    }
    result._length = result.calcDataLength();
    return result;
}

uint128_base10_t operator - (const uint128_base10_t &left, const uint128_base10_t &right) {
    uint128_base10_t result;
    if (left < right) {
        cout << "warning: left minus right but left is less than right, return zero" << endl;
    }
    else {
        uint8_t borrow(0);
        const uint8_t* leftData = left.getData();
        const uint8_t* rightData = right.getData();
        uint8_t* resultData = result._data;
        for (int i(0); i < uint128_base10_t::LENGTH; i++) {
            if (leftData[i] < rightData[i] + borrow) {
                resultData[i] = leftData[i] + 10 - (rightData[i] + borrow);
                borrow = 1;
            }
            else {
                resultData[i] = leftData[i] - (rightData[i] + borrow);
                borrow = 0;
            }
        }
    }
    result._length = result.calcDataLength();
    return result;

}

bool operator < (const uint128_base10_t &left, const uint128_base10_t &right) {

    const uint8_t* leftData = left.getData();
    const uint8_t* rightData = right.getData();
    bool ret = false;
    for (int i(uint128_base10_t::LENGTH - 1); i >= 0; i--) {
        if (leftData[i] < rightData[i]) {
            ret = true;
            break;
        }
        else if (leftData[i] > rightData[i]) {
            ret = false;
            break;
        }
    }

    return ret;

}
size_t uint128_base10_t::calcDataLength() const {
    int i;
    for (i = LENGTH - 1; i >= 0; i--) {
        if (_data[i] != 0) {
            break;
        }
    }
    if (i < 0) i = 0;
    return i+1;
}
uint128_base10_t uint128_base10_t::halfSplit(HALF h) const{
    uint128_base10_t result;
    size_t length = getDataLength();
    //if (length > 1 && length % 2 != 0) {
    //  cout << "warning: length = " << length << " is even" << endl;
    //}
    size_t even = (length % 2 != 0) ? 1 : 0;
    size_t halfLength = length / 2 + even;
    if (h == HALF::LOW) {
        memcpy(result._data, _data, halfLength);
        result._length = halfLength;
    }
    else {
        memcpy(result._data, _data + halfLength, halfLength - even);
        result._length = halfLength - even;
    }
    return result;
}

uint128_base10_t operator << (uint128_base10_t &left, int i) {
    uint128_base10_t result;
    for (int j(uint128_base10_t::LENGTH - 1); j >= 0 ; j--) {
        if (j - i >= 0)
            result._data[j] = left._data[j - i];
        else
            result._data[j] = 0;
    }
    result._length += i;
    return result;
}


uint128_base10_t operator *(const uint128_base10_t &left, const uint128_base10_t &right) {
    uint128_base10_t result;
    cout << left << " * " << right << endl;
    if (left.getDataLength() <= 1 && right.getDataLength() <= 1) {
        uint8_t temp = left._data[0] * right._data[0];
        result._data[2] = temp / 100;
        result._data[1] = (temp / 10) % 10;
        result._data[0] = temp % 10;
    }
    else {
        uint128_base10_t a = left.halfSplit(uint128_base10_t::HALF::HIGH);
        uint128_base10_t b = left.halfSplit(uint128_base10_t::HALF::LOW);
        uint128_base10_t c = right.halfSplit(uint128_base10_t::HALF::HIGH);
        uint128_base10_t d = right.halfSplit(uint128_base10_t::HALF::LOW);
        uint128_base10_t ac = a*c;
        int acShift = b.getDataLength() + d.getDataLength();
        uint128_base10_t bd = b*d;
        uint128_base10_t ad = a*d;
        int adShift = b.getDataLength();
        uint128_base10_t bc = b*c;
        int bcShift = d.getDataLength();
        uint128_base10_t acShiftRes = (ac << acShift);
        uint128_base10_t adShiftRes = (ad << adShift);
        uint128_base10_t bcShiftRes = (bc << bcShift);
        result = acShiftRes + bd + adShiftRes + bcShiftRes;
    }
    result._length = result.calcDataLength();
    return result;

}


ostream& operator << (ostream &out, const uint128_base10_t &d) {

    const uint8_t *data = d.getData();
    bool flag = false;
    for (int i(uint128_base10_t::LENGTH - 1); i >= 0; i--) {
        if (!(data[i] == 0 && flag == false)) {
            out << (char)(data[i] + 0x30);
            flag = true;
        }
    }
    if (flag == false)
        cout << 0;
    return out;
}

另外就是C++裏邊有幾點,以前一直沒有總結的。
就是下邊的代碼,t2和t3其實調用的都是Copy構造函數,而不是那個等號初始化會調用等號,t4=t1纔會調用等號

#include <iostream>
using namespace std;
class T {
    T() {cout << "1" << endl;}
    T(const T& t) {cout << "2" << endl;}
    T& operator = (const T& t) {cout << "3" << endl; return *this;};
};
int main() {
   T t1; // 輸出1
   T t2(t1); //輸出2
   T t3 = t1; //輸出2
   T t4; //輸出1
   t4 = t1; //輸出3
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章