Stanford Algorithms(一): 大數相乘(c++版)

來源:互聯網
上載者:User

標籤:desc   positive   gen   log   中間   故事   老師   lan   --   

Stanford Algorithms(一): 大數相乘(c++版)

剛不就在中國大學Mooc上參加了陳越老師的資料結構的課程,收穫很大.覺得趁熱打鐵,也把演算法的部分也給一塊學了吧,就在Coursera上註冊了一個斯坦福大學的演算法課,課程的量很重,估計要學一個學期吧,慢慢的學,穩紮穩打.

課程裡推薦了很多書,我找了一本, 書名就叫Algorithms,作者是S.Dasgupta教授,簡單翻看了一下,覺得寫的挺不錯,就姑且把這本書當做教材了.

還是那句話,貴精不貴多,一門學深入了,收穫就會很大,總之:

不要做一個浮躁的人.

第一節課就出了一個很有意思的題:兩個數相乘.

也許會有人問,這有什麼難,程式裡直接就能算,但是題目出的是兩個64個數字相乘,這就有意思了.

這個計算兩個數字相乘的演算法,視頻裡介紹過了,就是分治的思想,遞迴的調用,把原本的O(n^2)的問題變成了O(logn),效率無以提升很多.

我到網上一查,發現這是個很出名的,叫做大數相乘的演算法問題,參考了一些文章,但感覺寫的都不是很詳細.

我是用C++實現的.先看看思路吧:

1.數字太多,int肯定不行,要用string

2.具體的演算法已經有了,實現的困難,在於實現兩個string數字之間的加,減,以及乘法.

要用的函數大概是這些:

string multiply(string x, string y);string simplyMultiply(string x, string y);int string2int(string x);string int2string(int x);string add(string x, string y);string Minus(string x, string y);string addZero(string x, int zeroNum);string addPreZero(string x, int zeroNum);string reverseString(string s);int Max(int x, int y);

其中有三個函數比較簡單:

int Max(int x, int y){    /*     * Description: find max number     * Input: Two integers     * Output: Return max between x and y     */    return x > y ? x : y;}int string2int(string x){    /*     * Description: Change string to int     * Input: A string      * Output: Return a integer represents origin string     */    int n = x.length();    int s = 0;    for(int i = 0; i < n; ++i){        s = 10 * s + x[i] - ‘0‘;    }    return s;}string int2string(int x){    /*     * Description: Change int to string     * Input: An integers      * Output: Return a string represents origin integers     */    string result;    stringstream stream;    stream << x;    stream >> result;    return result;}

這裡藉助了stringstream,可以輕鬆實作類別型之間的轉換,當然是涉及到string的.

兩個string的加和減,考慮平時手算的方式,是尾對齊的,因此用程式實現的話,先把它們倒轉,變成頭對齊,就方便計算了.

string simplyMultiply(string x, string y){    /*     * Description: multiply two string, whose length = 1     * Input: Two string     * Output: Return product     */    if(x.empty() | y.empty()){        return int2string(0);    }else{        int result = string2int(x) * string2int(y);        return int2string(result);    }}string reverseString(string s){    /*     * Description: Reverse the string     * Input: A string     * Output: Return a reversed string     */    string result;    for(auto temp = s.end() - 1; temp >= s.begin(); --temp){        result.push_back(*temp);    }    return result;}

還有兩個額外的操作,就是在string前面和後面添加0,在前面添加0是為了讓兩個string的位元相等,因為這個演算法處理的是兩個等長string,因此要補位,不然會出問題;後面加0,是要用到與10^n相乘這種情況.

string addZero(string x, int zeroNum){    /*     * Description: Add zero between a string, simulate x * 10^n     * Input: A string, a integer represents zero‘s number after it     * Output: Return a string, which is added n‘s 0     */    string temp(zeroNum, ‘0‘);    x.append(temp);    return x;}string addPreZero(string x, int zeroNum){    /*     * Description: Add zero before a string to fill in empty place     * Input: A string, a integer represents zero‘s number     * Output: Return a string, which is added n‘s 0 before it     */    string temp(zeroNum, ‘0‘);    temp.append(x);    return temp;}

比較精彩的是類比兩個string加減的操作.有了前面幾個方法做鋪墊,實現起來就不困難了.其中,

Add操作模仿的是到10進1

Minus操作模仿的是減時不夠高位來補

細節一定要注意,否則bug很難看出來.

string add(string x, string y){    /*     * Description: Add two string     * Input: Two strings     * Output: Return their sum     */    int i, more = 0, tempSum = 0;    x = reverseString(x);    y = reverseString(y);    int maxSize = Max(x.size(), y.size());    string s(maxSize + 1, ‘0‘);    for(i = 0; i < x.size() && i < y.size(); ++i){        tempSum = x[i] - ‘0‘ + y[i] - ‘0‘ + more;        s[i] = tempSum % 10 + ‘0‘;        more = tempSum / 10;    }    if(i != y.size()){        for(; i < y.size(); ++i){            tempSum = y[i] - ‘0‘ + more;            s[i] = tempSum % 10 + ‘0‘;            more = tempSum / 10;        }    }else if(i != x.size()){        for(; i < x.size(); ++i){            tempSum = x[i] - ‘0‘ + more;            s[i] = tempSum % 10 + ‘0‘;            more = tempSum / 10;        }    }    if(more != 0){        s[i] += more;    }else{        s.pop_back();    }    s = reverseString(s);    return s;}string Minus(string x, string y){    /*     * Description: Minus between strings     * Input: Two strings     * Output: Return their difference     */    int i;    x = reverseString(x);    y = reverseString(y);    string s(x.size(), ‘0‘);    for(i = 0; i < y.size(); ++i){        if(x[i] < y[i]){            x[i] += 10;            x[i + 1] -= 1;        }        s[i] = x[i] - y[i] + ‘0‘;    }    for(; i < x.size(); ++i){        s[i] = x[i];    }    for(i = x.size() - 1; i > 0; --i){        if(s[i] == ‘0‘){            s.pop_back();        }else{            break;        }    }    s = reverseString(s);    return s;}

有了前面的這些,multi()寫起來就很簡單了,這裡要注意的是數字位元為奇數時的處理.

string multiply(string x, string y){    /*Description: Multiply between two strings     *Input: Two strings, represents two positive integers     *Output: Return product of x and y    */    int xSize = x.length();    int ySize = y.length();    int n = Max(xSize, ySize);    if(n == xSize){        y = addPreZero(y, n - ySize);    }else{        x = addPreZero(x, n - xSize);    }    if(n == 1){        return simplyMultiply(x, y);    }    string xLeft = x.substr(0, n / 2);    string xRight = x.substr(n / 2);    string yLeft = y.substr(0, n / 2);    string yRight = y.substr(n / 2);    string p1 = multiply(xLeft, yLeft);    string p2 = multiply(xRight, yRight);    string p3 = multiply(add(xLeft, xRight), add(yLeft, yRight));    string p4 = Minus(Minus(p3, p1), p2);    string result = add(add(addZero(p1, 2 * (n - n / 2)),                            addZero(p4, n - n / 2)), p2);    return result;}

現在,可以盡情的相乘了,兩個64位元也可以.

代碼在這裡:大數相乘

總結:以前很少考慮過兩個數是怎麼相乘的,寫在程式裡,也許只是一個符號而已,不知道這中間,發生了這麼多的故事.現在我們時常面臨著的,不是缺乏工具,而是工具封裝的太好,程式員都喜歡偷懶,但是要想獲得真正的提高,那個盒子,是遲早要開啟看看的.我覺得這是資料結構和演算法課,交給我的很重要的東西,這種底層的思維習慣,很重要.

Stanford Algorithms(一): 大數相乘(c++版)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.