目录
第一节 概述
杨辉三角是二项式系数在三角形中的一种几何排列,是中国古代数学的杰出研究成果之一。它把二项式系数图形化,把组合数内在的一些代数性质直观地从图形中体现出来,是一种离散型的、数与形的结合。
在实际计算杨辉三角时,最常使用的数学规律是:
-
除第1行只有唯一的元素1外,每行的首元素和尾元素都是1;
-
从第3行开始,中间的每一个元素是上一行左右2个元素的和。
由于杨辉三角的特殊性,我们采用链式队列结构存储与计算。
第二节 源代码
既然涉及到链式存储结构,首先要定义结点的数据存储格式。
每一个结点包含一个数据域和一个指针域,数据域用于存放队列的真实元素,指针域则指向队列中的下一个结点。
/**
* 编者注:
* 由于使用了C++作为编程语言
* 建议使用*.hpp作为头文件的后缀名
* *.h是C语言使用的头文件后缀名
*/
#pragma once
template <class DataType>
struct Node
{
DataType data;
Node<DataType> *next;
};
队列是一种具有操作限制的表结构:只能在队列开头删除元素(出队)、读取元素(读队头),只能在队列末尾添加元素(入队)。除了这些基本操作,队列还需要判空。
由于是链式存储,必须由我们自己编写构造函数与析构函数,用于开辟和释放队列的结点。
/**
* 编者注:
* 下面的类与上面的结构体是配套的
* 强烈建议放在同一个头文件中
*/
template <class DataType>
class LinkQueue
{
private:
Node<DataType> *front, *rear; //队头、队尾指针
public:
LinkQueue(); //构造函数,初始化一个空的链队列
~LinkQueue(); //析构函数,释放链队列中各结点的存储空间
void EnQueue(DataType x); //将元素x入队
DataType DeQueue(); //将队头元素出队
DataType GetQueue() const; //取链队列的队头元素
bool Empty() const; //判断链队列是否为空
};
#include <iostream>
#include <iomanip> //输出格式设置
/**
* 记得在此处引入上面的头文件(建议使用*.hpp)
*/
using namespace std;
template <class DataType>
LinkQueue<DataType>::LinkQueue()
{
Node<DataType> *s = new Node<DataType>;
s->next = nullptr;
front = rear = s;
}
template <class DataType>
LinkQueue<DataType>::~LinkQueue()
{
Node<DataType> *p = nullptr;
while (front != nullptr)
{
p = front->next;
delete front;
front = p;
}
}
template <class DataType>
void LinkQueue<DataType>::EnQueue(DataType x)
{
Node<DataType> *s = new Node<DataType>; //申请节点s
s->data = x; //将数据存入结点
s->next = nullptr; //封闭队尾
rear->next = s; //将新节点接入原队尾
rear = s; //更新队尾
}
template <class DataType>
DataType LinkQueue<DataType>::DeQueue()
{
Node<DataType> *p = nullptr;
DataType x;
if (rear == front)
throw "错误:下溢!";
p = front->next;
x = p->data; //暂存队头元素
front->next = p->next; //摘链
if (p->next == nullptr)
rear = front;
delete p;
return x;
}
template <class DataType>
DataType LinkQueue<DataType>::GetQueue() const
{
if (front != rear)
return (front->next->data);
else
throw "错误:空队列!";
}
template <class DataType>
bool LinkQueue<DataType>::Empty() const
{
return (front == rear);
}
现在,终于到了解释主算法的时候了!每一句的逻辑都注释在代码中:
//杨辉三角,其中n是总行数
void nCr(int n)
{
LinkQueue<int> queue; //初始化空队列
for (auto i = 1; i <= n; i++) //对于每一行
{
if (i == 2) //在第2行时
{
cout << setw(3) << queue.DeQueue() << endl;
queue.EnQueue(1); //加上行首的元素1
}
else if (i > 2) //第3行及之后
{
queue.EnQueue(1); //补上行首的元素1
for (auto j = 1; j <= (i - 2); j++) //每行的求和元素比行序号少2
{
auto temp = queue.DeQueue(); //将求和元素的左元素(上一行)出队并另存
cout << setw(3) << temp << " ";
queue.EnQueue(temp + queue.GetQueue()); //读取右元素(上一行),将左右元素相加并入队
}
cout << setw(3) << queue.DeQueue() << endl; //输出上一行末尾的元素1
}
queue.EnQueue(1); //在行尾补元素1
}
//若队列非空,输出最后一行的元素
while (!queue.Empty())
{
cout << setw(3) << queue.DeQueue() << " ";
}
cout << endl
<< endl;
}