|
→ |
| ↓ |
|
|
* |
|
|
|
* |
* |
* |
|
| * |
* |
* |
* |
* |
|
* |
* |
* |
|
|
|
* |
|
|
|
總結了一下關於列印菱形的思路。
通常是從迴圈變數之間的映射關係入手,推匯出相應的公式。這種思路的源點,往往會將座標軸的原點放在左上方,也就是在[2N + 1]的矩形內列印出內嵌的菱形。如所示,橫向[row]的取值範圍[0, 2N+1),縱向[col]的取值範圍[0, 2N + 1),變數[N]表示要列印菱形對角線長的1/2。
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
| 0 |
|
|
|
* |
|
|
|
| 1 |
|
|
* |
* |
* |
|
|
| 2 |
|
* |
* |
* |
* |
* |
|
| 3 |
* |
* |
* |
* |
* |
* |
* |
| 4 |
|
* |
* |
* |
* |
* |
|
| 5 |
|
|
* |
* |
* |
|
|
| 6 |
|
|
|
* |
|
|
|
照此思路有如下幾種解法:
解法一:將菱形從中間分開,可以看到[輸出空格數 + 星號數 = N](*從零計數)。那麼可以將空格輸出和星號輸出分別進行。
[空格輸出]的控制變數由[col]完成。對應的輸出條件[col < abs(row - N)]。
[星號輸出]的控制變數亦由[col]完成。對應的輸出條件[col < (2 * (N - abs(row - N)) + 1]。
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
| 0 |
|
|
|
* |
|
|
|
| 1 |
|
|
* |
* |
* |
|
|
| 2 |
|
* |
* |
* |
* |
* |
|
| 3 |
* |
* |
* |
* |
* |
* |
* |
| 4 |
|
* |
* |
* |
* |
* |
|
| 5 |
|
|
* |
* |
* |
|
|
| 6 |
|
|
|
* |
|
|
|
★ 代碼如下:
/* 這裡將菱形從中切開,比較容易尋找到規律。*/#include <stdio.h>#include <math.h>int main(void){ int count, row, col; printf("Number of rows = ?\n"); scanf("%d", &count); for (row = 0; row < (count * 2 + 1); row++) { // 控制空格的輸出 for (col = 0; col < abs(row - count); col++) { printf(" "); } // 控制 * 號的輸出 for (col = 0; col < (2 * (count - abs(row - count)) + 1); col++) { printf("*"); } printf("\n"); } return 0;}
解法二:認為是在一個[2N + 1]的矩形畫布上輸出菱形。鑒於菱形的對稱特性,利用座標之間的不等式關係,可以找到每一個星號的可能的輸出範圍。
那為例,
[紅色*座標] [row, col] = [0, 3] ==> (row + col) = 3
[藍色*座標] [row, col] = [6, 3] ==> (row + col) = 9
由此可知 (row + col) ∈ [N, 3 * N]
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
| 0 |
|
|
|
* |
|
|
|
| 1 |
|
|
* |
* |
* |
|
|
| 2 |
|
* |
* |
* |
* |
* |
|
| 3 |
* |
* |
* |
* |
* |
* |
* |
| 4 |
|
* |
* |
* |
* |
* |
|
| 5 |
|
|
* |
* |
* |
|
|
| 6 |
|
|
|
* |
|
|
|
但對於兩個變數[row]和[col]而言,顯然一個條件式並不能夠正確的定位,現在需要構建另一個條件式。
仍以為例,可以得到對應的條件式
[紅色*座標] [row, col] = [0, 3] ==> (row - col) = -3
[藍色*座標] [row, col] = [6, 3] ==> (row - col) = 3
由上可以推得 (row - col) ∈ [-N, N]
到這裡兩個控制變數被限制在了兩個條件式中,這時就可以正確的定位到每一個星號的位置了。
★ 代碼如下:
#include <stdio.h>int main(void){ int row, col, count; printf("Number of rows = ?\n"); scanf("%d", &count); for (row = 0; row < (2 * count + 1); row++) { for (col = 0; col < (2 * count + 1); col++) { // 這裡要求輸出 * 的位置滿足[count <= (row + col) <= 3 * count]&&[-count <= (row - col) <= count] if (count <= (row + col) && (row + col) <= 3 * count && -count <= (row - col) && (row - col) <= count) { printf("*"); } else { printf(" "); } } printf("\n"); } return 0; }
以上兩種解法預設座標系在左上方,實際可以平移座標系,使得橫縱座標之間的關係能夠更好的表達。如
|
-3 |
-2 |
-1 |
0 |
1 |
2 |
3 |
| -3 |
|
|
|
* |
|
|
|
| -2 |
|
|
* |
* |
* |
|
|
| -1 |
|
* |
* |
* |
* |
* |
|
| 0 |
* |
* |
* |
* |
* |
* |
* |
| 1 |
|
* |
* |
* |
* |
* |
|
| 2 |
|
|
* |
* |
* |
|
|
| 3 |
|
|
|
* |
|
|
|
解法三:觀察在新的座標系中,每個星號所在的橫縱座標之間的關係可以表示為[row + col <= N]
[紅色*座標] [row, col] = [0, -3] ==> (row + col) = -3
[藍色*座標] [row, col] = [3, 0] ==> (row + col) = 3
由此可知 (abs(row) + abs(col)) ∈ [0, N]
以上兩種解法預設座標系在左上方,實際可以平移座標系,使得橫縱座標之間的數值關係能夠更好的表示。如
|
-3 |
-2 |
-1 |
0 |
1 |
2 |
3 |
| -3 |
|
|
|
* |
|
|
|
| -2 |
|
|
* |
* |
* |
|
|
| -1 |
|
* |
* |
* |
* |
* |
|
| 0 |
* |
* |
* |
* |
* |
* |
* |
| 1 |
|
* |
* |
* |
* |
* |
|
| 2 |
|
|
* |
* |
* |
|
|
| 3 |
|
|
|
* |
|
|
|
★ 代碼如下:
/** 靈活運用座標系可以簡化程式。**/#include <stdio.h>#include <math.h>int main(void){ int row, col, count; printf("Number of row count = ?\n"); scanf("%d", &count); for (row = -count; row <= count; row++) { for (col = -count; col <= count; col++) { if (abs(row) + abs(col) <= count) { printf("*"); } else { printf(" "); } } printf("\n"); } return 0;}
下面的方法充分利用了[printf函數]本身提供的功能,可以實現極其精簡的代碼。
解法四:採用通常預設的座標方式來表示變數之間的關係。
映射關係
| row |
輸出寬度 |
輸出寬度函數關係 |
星號個數 |
模板星號 |
需要刪除星號個數 |
刪除星號個數函數關係 |
| 0 |
5 |
row + N + 1 |
1 |
********* |
8 |
2 * N - 2 * row |
| 1 |
6 |
3 |
6 |
| 2 |
7 |
5 |
4 |
| 3 |
8 |
7 |
2 |
| 4 |
9 |
9 |
0 |
| 5 |
8 |
(3 * N + 1) - row |
7 |
2 |
2 * row - 2 * N |
| 6 |
7 |
5 |
4 |
| 7 |
6 |
3 |
6 |
| 8 |
5 |
1 |
8 |
對應的關係列出後,就很容寫出對應的代碼了。
★ 代碼如下:
#include <stdio.h>int main(void){ int row, col, count; int i = 0; char a[100]; printf("Number of rows = ?\n"); scanf("%d", &count); for (; i != (2 * count + 1); i++) { a[i] = '*'; } row = 0; for (; row != (2 * count + 1); row++) { printf("%*s\n", (row < (count + 1)?(row + count + 1):((3 * count + 1) - row)), a + (row < (count + 1)?(2 * count - 2 * row):(2 * row - 2 * count))); }}
解法五:採用座標軸平移後的方式來表示變數之間的關係。
映射關係
| row |
輸出寬度 |
輸出寬度函數 |
星號個數 |
|
星號模板 |
要刪除的星號個數 |
刪除星號個數函數關係 |
| -4 |
5 |
(2 * N + 1) - abs(row) |
1 |
(2 * N + 1) - abs(row) - abs(row) |
********* |
8 |
2 * abs(row) |
| -3 |
6 |
3 |
6 |
| -2 |
7 |
5 |
4 |
| -1 |
8 |
7 |
2 |
| 0 |
9 |
9 |
0 |
| 1 |
8 |
7 |
2 |
| 2 |
7 |
5 |
4 |
| 3 |
6 |
3 |
6 |
| 4 |
5 |
1 |
8 |
依上表對應關係,經過座標平移後的對應關係更加簡潔,代碼量更小。
★ 代碼如下:
#include <stdio.h>#include <math.h>intmain(void){ int row, col, count; int i; char p[100]; printf("Number of rows = ?\n"); scanf("%d", &count); i = 0; for (; i != (2 * count + 1); i++) { p[i] = '*'; } row = -count; for (; row <= count; row++) { printf("%*s\n", ((2 * count + 1) - abs(row)), p + (2 * abs(row))); } return 0;}
★ 以上代碼均在 Ubuntu 10.04 下編譯通過。