關於書寫的規範性算法
清晰的書寫+清晰的佈局+合理的命名編程
一、清晰的書寫:在手寫代碼時先造成清晰的思路並把思路用編程語言清晰的寫出來,字跡清晰編程語言
二、清晰的佈局:合理的縮進、空格、空行(循環塊 定義變量塊 等)ide
三、合理的命名:用完整的英文單詞組合命名變量和函數,一眼就能夠看出變量、函數的用途函數
代碼完整性佈局
1.在編寫代碼以前考慮單元測試,一般咱們能夠從功能測試、邊界值測試和負面測試三方面設計測試用例,以確保代碼完整性單元測試
*功能測試:檢查代碼是否實現基本功能測試
*邊界值測試:輸入一些邊界值(結束循環的邊界條件、遞歸終止邊界)看代碼是否符合條件spa
*負面測試:輸入不合法的值看代碼運行狀況(是否能作出合理的錯誤處理)設計
將代碼未來的可能的需求所有考慮,在需求變化是時能儘可能減小代碼改動的風險,使程序可擴展與可維護
位運算
與& | 0&0=0 | 1&0=0 | 0&1=0 | 1&1=1 |
或| | 0|0=0 | 1|0=1 | 0|1=1 | 1|1=1 |
異或^ | 0^0=0 | 1^0=1 | 0^1=1 | 1^1=0 |
題目:1
實現一個函數,輸入一個整數,輸出該數的二進制表示中1的個數,例如9的二進制是1001,有兩個1,輸入9,輸出1
程序1.0
寫法1:模除法 int CountOne(int n) { int count = 0; while (n) { int ret = 0; ret = n % 2; if (1 == ret) count++; n /= 2; } return count; }
程序2.0
位運算,因爲除法的效率要遠遠低於位運算,因此在須要用乘除時儘可能用位運算代替
而右移運算符又會引入一個新問題,若輸入一個負數,則會致使無限循環(右移時左邊補符號位)
int CountOne(int n) { int count = 0; while (n) { if ((n & 1) == 1) { count++; } n=n >> 1; } return count; }
算法2.1
位運算改進,不對輸入的數進行移位
int CountOne(int n) { int count = 0; size_t flag = 1; while (flag) { if (n&flag) count++; flag <<= 1; } return count; }
算法3.0
把一個整數減去1,再和原整數作與運算,會把該整數的最右邊的一個1變成0,那麼一個整數的二進制表示中有多少個1,就能夠作多少次這樣的操做
int CountOne(int n) { int count = 0; while (n) { ++count; n = (n - 1)&n; } return count; }
*把一個整數減去1再和原來的整數作位與運算獲得的結果至關於把這個整數中表示最右邊的一個1變成0
舉一反二
用一條語句判斷一個整數是否是2的整數次方,一個整數若是是2的整數次方那麼它的二進制表示中有且僅有一位是1,其餘位都是0;
分析:這個數減去1再和本身位與,這個整數中惟一的1就會變成0
2. 輸入兩個整數n和m,計算須要改變m的二進制表示中的多少位才能獲得n,好比10的二進制位1010,13的二進制1101,須要1010改變3位才能獲得1101,
分析:第一步求這兩個數的異或,第二部統計異或結果中1的位數
題目二
實現函數double Power(double base,int exponen),求base的exponent次方,不得使用庫函數,同時不須要考慮大數問題
程序1.0
最簡單的寫法,可是仍是沒有考慮效率的問題
double Power(double base, int exponen) { double ret = 1.0; double ex = 0.0000000001;//考慮base等於0的時候 if (base<ex&&base>-ex) return 0; if (exponen > 0) { while (exponen > 0) { ret *= base; exponen--; } return ret; } if (exponen < 0) { while (exponen < 0) { ret *= (1.0 / base); exponen++; } return ret; } else return 1; }
程序2.0
採用全局變量來標識是否出錯,若出錯則返回0,,設置爲全局的好處是能夠把函數直接傳遞給其餘變量
同時,浮點數在判斷是否相等時,採用比較它們的差是否在一個很小的範圍內,若兩數相差很小則判斷相等
bool q_InvalidInput = false; double PowerWithUnsignedExponent(double base, unsigned int exponent) { double result = 1.0; for (int i = 1; i <= exponent; i++) { result *= base; } return result; } bool equal(double num1, double num2) { if ((num1 - num2 > -0.000000001) && (num1 - num2 < 0.000000001)) return true; else return false; } double Power(double base, int exponent) { q_InvalidInput = false; if (equal(base, 0.0) && exponent < 0)//判斷輸入的是不是0,如果,則在exponent<0時直接返回0 { q_InvalidInput = true; return 0.0; } unsigned int absExponent = (unsigned int)(exponent); if (exponent < 0) { absExponent = (unsigned int)(-exponent);//將負數去符號 } double result = PowerWithUnsignedExponent(base, absExponent); if (exponent < 0) { result = 1.0 / result; } return result; }
程序2.1
用位操做符
在上面函數中用一次次的循環來乘出結果,若要算32的次方,咱們就要作31次乘法,若是已經知道16這次,只要在16次方的基礎上再平方一次,而16是8的次方……
改寫PowerWithUnsignedExponent()
double PowerWithUnsignedExponent(double base, int exponent) { if (exponent == 0) return 1; if (exponent == 1) return base; double result = PowerWithUnsignedExponent(base, exponent >> 1);//右移1位表示除以2 result *= result; if (exponent & 0x1 == 1)//用位與代替求餘(%),來判斷是奇數仍是偶數 result *= base; return result; }