數字菱形圖案(雙重循環)(C++)
//找到一道比較有代表性的,較為全面的繪制圖形,並且控制繪制字符在變化的題目,驚喜。
【問題描述】
編程打印用數字構成的菱形圖案,菱形上半部分的行數n( 1<n<10 )從鍵盤輸入,總行數為2n-1。圖案的樣式按下面的樣例。
【輸入形式】
從鍵盤輸入包括中間一行在內的菱形上半部分的行數n ( 1<n<10 )。
【輸出形式】
輸出用數字構成的菱形圖案,樣式按下面的樣例,其中各數字間用1個空格間隔,中間一行的起始數字1位於第1列。
【樣例輸入】
4
【樣例輸出】
1
1 2 1
1 2 3 2 1
1 2 3 4 3 2 1
1 2 3 2 1
1 2 1
1
解題思路(繪制圖形的題套用)
-
把圖形分塊:(不是唯一分塊法)
1| 1 2| 1 1 2 3| 2 1 1 2 3 4| 3 2 1 —————————————— 1 2 3| 2 1 1 2| 1 1|
-
把分成四塊的菱形,每塊三角形單獨寫出代碼(通用循環格式:for循環,i表示行數,j表示列數)
先給出完整代碼:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n;//上半部分行數
cin >> n;
for( int i=1; i <= n; ++i )
{
cout << setw( 2*(n-i)+1 );//打印空格
for( int j=1; j <= i; ++j )//左上三角形
cout << " " << j;
for( int j=i-1; j > 0; --j )//右上三角形
cout << " " << j;
cout << endl;//一行結束換行
}
for( int i=1; i <= n-1; ++i )
{
cout << setw( 2*i+1 );//打印空格
for( int j=1; j <= n-i; ++j )//左下三角形
cout << " " << j;
for( int j=n-i-1; j > 0; --j )//右下三角形
cout << " " << j;
cout << endl;//一行結束換行
}
}
詳解:
左上三角形:
(TIP:先行提醒一下setw()的用法,不是調用setw(6)就空6個空格,而是表示設域寬為6個字符,如果后面連續輸出其他字符,這會在域寬中從右到左覆蓋“空格”)
//可以自己用以下這個代碼自行體驗測試
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int a=6;
cout<<setw(1)<<a<<endl;
cout<<setw(2)<<a<<endl;
}
#include <iostream>
#include <iomanip>//使用控制符時,要在程序的頭上加專門的頭文件
using namespace std;
int main()
{
int n;
cin >> n;//接下來以用戶輸入的n是4,即樣例輸出的菱形來做說明
for( int i=1; i <= n; i++ )//作為左上三角形,行數明顯與n一樣,所以使i循環n次
{
cout << setw( 2*n-2*i+1 );//setw()即設域寬為()個字符,數格子找規律
//(找規律的詳解見代碼結束后的表格)
for( int j=1; j <= i; j++ )//定義列數j和每列輸出的字符
cout << " " << j;//注意題目要求是每個字符之間都有空格
cout << endl;//換行不能在for j 的循環里面,應該是每完全輸出一行,才考慮換行
}
}
以n=4為例:
行數i | 空格數 |
---|---|
1 | 7 |
2 | 5 |
3 | 3 |
4 | 1 |
普遍推廣到n:
(注意:空格數肯定是跟n和i有聯系的,就往這上面湊)
行數i | 空格數 |
---|---|
1(1=n-(n-1)) | 2*(n-1)+1 |
2(2=n-(n-2)) | 2*(n-2)+1 |
… | … |
n-2 | 5 |
n-1 | 3 |
n | 1 |
概括的規律:
空格數=2*(n-i)+1
即setw(2*(n-i)+1)
(后面幾個找規律都是按這樣的思路來一一列表找,之后就不再如此反復地解釋)
右上三角形:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n;
cin >> n;
for( int i=1; i <= n; i++ )//行數循環
{
//注意,以左上的三角形為參考,則右上的三角形第一行不能輸出東西,在第二行才開始輸出
for( int j=i-1; j > 0; j-- )//列數j循環,而且我不想再多設置一個變量,就直接把j當作輸出的東西一起來循環
//首先要保證循環的列數是從1到i-1,其次要保證輸出的字符是左邊三角形最大的數減1的那個數(即i-1)
cout << " " << j;
cout << endl;
}
}
}
左下三角形:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n;
cin >> n;
for( int i=1; i <= n-1; i++ )//只要輸出n-1行
{
cout << setw( 2*i+1 );//每行前面的“空格”找規律(肯定是一個與i有關的式子)
for( int j=1; j <= n-i; j++ )
cout << " " << j;
cout << endl;
}
}
右下三角形:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n;
cin >> n;
for( int i=1; i <= n-1; i++ )
{
for( int j=n-i-1; j > 0; j-- )//同右上三角形,不僅j控制列數循環次數,而且控制輸出字符,找個規律就很容易得答案了
cout << " " << j;
cout << endl;
}
}
- 模塊組合:我們把以上四個小塊組合在一起,就很容易得到完整的菱形了。
**思路:**上下關系的模塊在main()函數內按順序並列排,左右關系的模塊在for i 循環內按順序並列排,先內左右,后外上下,刪除相同的代碼,保留不同的部分。
模塊關系解釋:
左上為 ① | 右上為② |
---|---|
左下為③ | 右下為④ |
則①②為左右關系,③④也為左右關系,①②與③④則為上下關系。
PS:這樣就搞定了
推廣用法,菱形是比較全面的模型:
- 如果只是輸出左上三角,左下三角,怎么組合代碼呢?
- 如果不輸出數字,而全部用“#”代替會變化的數字輸出,怎么改代碼呢?
- 如果每個輸出字符之間不要留空格,怎么尋找循環規律呢?
- 如果打九九乘法表,怎么組合模塊呢?