寫**,有兩類追求,一種是追求實用(coder),一種是追求**藝術(artist)我是那種追實用追膩了,偶然追一下藝術(就是偶然和藝術有一腿)的那種coder
很多人,已經習慣了for(i=0; i= n;
}又或者,有的人知道平方根的優化:
int isprime(int n)
再或者,消除偶數:int isprime(int n)
當然,這樣還不是很夠的話,我們可以考慮這個事實:
所有大於4的質數,被6除的餘數只能是1或者5
比如接下來的5,7,11,13,17,19都滿足
所以,我們可以特殊化先判斷2和3
但後面的問題就出現了,因為並非簡單的遞增,從5開始是+2,+4,+2,+4,....這樣遞增的
這樣的話,迴圈應該怎麼寫呢?
首先,我們定義乙個步長變數step,迴圈大概是這樣 for (i = 5; i <= s; i += step)
那麼,就是每次迴圈,讓step從2變4,或者從4變2
於是,可以這麼寫:
#include #include int isprime(int n)
return i > s;
}int main()
getchar();
return 0;
}如上**,乙個 step ^= 6; 完成step在2和4之間轉換(這個 ^ 符號是c裡的異或運算)
理由是,2化二進位制是010,4是100,6是110,於是2異或4得到6:
2 ^ 4 => 6
6 ^ 2 => 4
6 ^ 4 => 2
於是利用異或,就可以構造這種步長在兩個值之間來回變化的迴圈
思考題:前面說的是雙值迴圈,那麼如何構造三值或者四值迴圈?
2.菱形列印
很多人,列印菱形在控制台的思路是,把菱形上下拆分,分兩段很接近的**來列印,
其實這樣**很不好看,並且不好閱讀
我們知道,要列印的圖案是這種:
****
*****
****
滿足上下對稱,左右對稱,那麼,你能不能也弄乙個二重迴圈,同樣是對稱的?
很簡單,首先我們要拋開習慣性思維,for迴圈不一定要在0開始或者0結束
我們可以讓迴圈從 -c 到 c ,這樣不就輕鬆產生乙個對稱的嗎?(只要取個絕對值)
我們把菱形的中心看成是座標0,0,那麼,會輸出星號的座標,是 |x| + |y| <= c 的點
由此可得
#include #define iabs(x) ( (x) >= 0 ? (x) : -(x) ) //定義乙個計算絕對值的巨集
void print(int size) // size是這個菱形的半徑,直徑會是size * 2 + 1
putchar('\n');
}}int main()
如果我需要得到空心菱形呢?非常非常簡單,因為菱形邊界上的點,滿足的是|x| + |y| == c
所以,我們只要把那個if裡的小於等於號,改成雙等於號 == 就可以了
再類似地,如果我不要*號,我要最外層是字母a,然後裡一層是b這樣呢?即:
aaba
abcba
abaa
那麼,我們只要在putchar那裡做乙個字元計算:
void print(int size) // size是這個菱形的半徑,直徑會是size * 2 + 1
putchar('\n');
}}類似地,如果我們要列印的是x形:
* *
* **
* ** *
同樣可以利用這個思路完成,這題就作為思考題吧
3. 奇數階幻方
所謂幻方(最基本的那種),就是橫,豎,對角線上的數的和等於乙個常數的數字方陣
4 3 8
9 5 1
2 7 6
以上這個圖,有什麼規律?容易寫成**嗎?
我們把這個圖,向右複製五次,向下複製三次,展開一下:
4 3 8 4 3 8 4 3 8 4 3 8 4 3 8
9 5 [1] 9 5 1 9 5 1 9 5 1 9 5 1
2 7 6 [2] 7 6 2 7 6 2 7 6 2 7 6
4 3 8 4 [3] 8 [4] 3 8 4 3 8 4 3 8
9 5 1 9 5 1 9 [5] 1 9 5 1 9 5 1
2 7 6 2 7 6 2 7 [6] 2 [7] 6 2 7 6
4 3 8 4 3 8 4 3 8 4 3 [8] 4 3 8
9 5 1 9 5 1 9 5 1 9 5 1 [9] 5 1
2 7 6 2 7 6 2 7 6 2 7 6 2 7 6
注意中括號數字的走向
怎麼樣,現在呢?
現在看起來顯得規律性強了很多,但是,你會不會覺得迴圈還是不太好寫?
我們如何從乙個給定的n,直接得知它的座標呢?
不難,找一下規律就可以發現對於任意的數值n+1有(以左上角為0,0座標):
x = 2 + n + n / 3;
y = 1 + n - n / 3;
其實這個規律可以簡單擴充套件到任意奇數階幻方(以下size是奇數):
x = size / 2 + 1 + n + n / size; (注意這裡的除法是取整除法,不帶小數)
y = size / 2 + n - n / size;
這樣,我們就可以把原來複雜的迴圈,化簡成一重簡單迴圈
於是有程式:
#include #define size 5 //定義幻方階數,這個數只能是奇數
int main()
//以下是輸出
for (y = 0; y < size; y++)
return 0;
}這個比你網上能找到的很多求奇數階幻方的**都短小很多(不過網上較多稱之為魔方陣,不知為何)
4. 字串迴圈移位
問題,給你乙個字串,要求迴圈左移n位
比如對"abcdefg" 迴圈左移2位,我們要得到"cdefgab"
附加條件,不能使用連續輔助空間(包括動態分配),只能使用若干單個變數(即o(1)空間)
首先,我們知道,反轉乙個字串操作("abcd"變"dcba"),是不需要額外陣列輔助的,只要頭尾資料交換就可以了
然而,可能你不知道,僅僅使用字串反轉可以實現字串迴圈移位:
//反轉字串,把st與ed所指向的中間的內容反轉(包含st不包含ed)
void str_rev(char* st, char *ed)
}//用三反轉等效左移字串(st與ed之間,包含st不包含ed的內容)
char* str_shl(char* st, char* ed, int n)
#include #include int main()
這裡,如果要迴圈左移n位,只要把原來字串分成兩段,前n字元,和後面其它字元
兩段分別反轉,最後再整體反轉,就實現了迴圈左移(如果先整體再兩部分,就是迴圈右移)
而在那個字串反轉函式裡,參與迴圈的,不再是int,而是兩個指標,
為什麼選擇使用兩個指標呢?如果你寫乙個str_rev(char* str, int len)的版本,相信你就明白了,這裡不多廢話
for迴圈小技巧
for迴圈 語法 for 表示式1 表示式2 表示式3 迴圈體表示式1一般為宣告迴圈變數,記錄迴圈的次數 int i 0 表示式2一般為迴圈條件 i 10 表示式3一般為改變迴圈條件的 使之終有一天不再成立 i 執行過程 程式首先執行表示式1,宣告了乙個迴圈變數用來記錄迴圈的次數,接著執行表示式2,...
c語言中迴圈使用技巧
簡明來說不確定迴圈,不知道何時迴圈停止,而計數迴圈已知要執行多少次迴圈 其中涉及了三個重要部分 1.初始化計數器 2.計數器與有限值比較 3.每次迴圈對計數器進行有規律變化 下面用for迴圈進行舉例 for i 0 i 10 i for i 0 i 10 i 見課本習題五p138頁 17題 incl...
C語言中的小技巧
看看下面一段程式的功能 testrcunit.cpp 定義控制台應用程式的入口點。include typedef void cunit test case func type brief 測試用例鍊錶結點。儲存測試用例的函式指標和測試用例的名字。typedef struct tagcunittest...