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;
}

综上,感谢观看。