C++/C — 杨辉三角
杨辉三角是二项式系数在三角形中的一种几何排列。杨辉三角通过把二项式系数图形化,使组合数内在的一些代数性质直观地从图形中体现出来,是一种离散型的数与形的结合。下表在欧洲也被称作帕斯卡三角形。
杨辉三角最大的特点是:
每个数字等于上一行的左右两个数字之和。可用此性质写出整个杨辉三角。
即第 n + 1 行的第 i 个数等于第 n 行的第 i - 1 个数和第 i 个数之和。
在用算法打印杨辉三角时,就是用 C(n + 1, i) = C(n, i) + C(n, i - 1)的思想。
杨辉三角的数学意义
斐波那契数列
将杨辉三角按如下图所示划出斜线,再求出斜线所经过的数字的和:1,1,2,3,5,8,13,21
此数列就是著名的 斐波那契数列 。

斐波那契数列中,从第三个数起,每个数与它后面那个数的比值,都很接近于0.618,正是黄金分割 。
因此斐波那契数列又称 黄金分割数列 。
这个看上去很简单的数列,总是出现在人们的眼前。蜻蜓翅膀、蜂巢、菠萝表面的突起等,都是按照这个数列排列的。许多花朵的花瓣数目也具有斐波纳契数列的排列规律,如玫瑰、菊花、向日葵等。
谢尔宾斯基三角形
杨辉三角除了在数值上蕴藏了斐波那契数列的奥秘,在几何上也体现了谢尔宾斯基三角形的数学之艺术美。
谢宾斯基三角形(Sierpinski triangle)是一种分形,由波兰数学家谢宾斯基在1915年提出。它是一种自相似集。

如果用笔将杨辉三角中的偶数与奇数分别标出,可以看到所有的偶数都会呈现出倒立的等边三角形状排列,而奇数都成正立的三角形排列,且等边三角形(偶数)的边长依次为:3,7,15,31,63…即所有的偶数依次排出以(2的n次幂-1)的长度为边长的倒立的等边三角形。
将所有等边三角形中的偶数去掉,剩下的图形是一个类似于分形几何中的谢尔宾斯基三角形,这种三角形是研究自然界大量存在的不规则现象(海岸线性状、大气运动、海洋湍流、野生生物群体涨落,股市升降等)的崭新数学工具。

用算法打印出杨辉三角
简单了解了什么是杨辉三角后,我们尝试用算法将杨辉三角打印出来。当输入一个数 n 时,打印出 n 行杨辉三角。
下面介绍三种简单易懂的方式打印杨辉三角:
- 二维数组法
- 递归法
- 公式法
二维数组法
#include < bits/stdc++.h >
using namespace std;
int main()
{
int n;
cin>>n;
int a[100][100];
a[0][0]=1;
a[1][0]=1;
a[1][1]=1;
if(n==1) cout<<"1"<< endl;
else if(n==2) cout<<"1"<< endl<<"1 1"<< endl; //单独打印无规律的前两排
else
{
cout<<"1"<< endl<<"1 1"<< endl;
for(int i=2;i< n ;i++)
{
for(int j=0;j < i+1;j++)
{
if(j==0||j==i+1) a[i][j]=1;
else a[i][j]=a[i-1][j-1]+a[i-1][j]; //每个数字等于上一行的左右两个数字之和
}
}
for(int i=2;i < n;i++)
{
for(int j=0;j < i+1;j++)
{
cout<< a[i][j] <<" "; //打印杨辉三角
}
cout<< endl;
}
}
return 0;
}
递归法
递归写法的思路和第一种二维数组的写法思路相似
我们把杨辉三角的所有元素全部都看成两类元素:第一类是对角线和第一列的1,第二类是其他的元素。
第二类的元素是由上面的 arr [ i - 1 ] [ j ] + arr [ i - 1] [ j - 1] 构成的,
所以我们在用递归写的时候,当满足条件的时候就返回1,不满足的时候就返回上两个元素的和。
代码展示如下
#include < stdio.h >
int fun(int m, int n)
{
//除了对角线和第一列之外,其他元素都是上两个数字之和
if (n == 0 || m == n)
return 1;
else
return fun(m - 1, n) + fun(m - 1, n - 1);
}
int main()
{
int i, j;
int n = 0;
scanf("%d", &n);
for (i = 0; i < n; i++)
{
for (j = 0; j < n - 1 - i; j++)
{
printf(" ");
}
for (j = 0; j <= i; j++)
printf("%d ", fun(i, j));
printf("\n");
}
return 0;
}
公式法
#include< stdio.h >
int fun2(int num)
{
int sum = 1;
for (int i = 1; i <= num; i++)
{
sum *= i;
}
return sum;
}
int fun(int n, int m)
{
int ret = fun2(n);
int dat = fun2(m);
int un = fun2(n - m);
//公式:C(n - 1, m - 1) = (n - 1)!/ [(m - 1)!(n - m)!]
return ret / (dat * un);
}
int main()
{
int i = 0;
int j = 0;
int n = 0;
scanf("%d", &n);
//这里i和j要从1开始,否则公式就会出现求负数的阶乘
for (i = 1; i <= n; i++)
{
for (j = 0; j < n - 1 - i; j++)
{
printf(" ");
}
for (j = 1; j <= i; j++)
{
int C = fun(i - 1, j - 1);
printf("%d ", C);
}
printf("\n");
}
return 0;
}
综上,感谢观看。
