双链表求500位Π
题目描述:

思路分析:
根据上面给出的公式,我们可以知道每一项都是前一项乘
但是考虑到会出现的大数,不能直接用long long来进行存储,绝对会溢出。又题目限定了使用双链表,因此我们使用双链表。
最主要需要解决的问题是大数的加法、乘法除法。解决方案见下。
另外,可以给第一项直接乘6,这样之后每一项都是原来的6倍,得出来的结果直接位Π,不必再继续乘。
并且我们数字低位在前,高位在后。
解题过程:
①完成一个双链表,题目中要求前500位,那么我们定义一个有600个节点的双链表,并将其初始化。
struct Node
{
int data = 0;
Node* next = nullptr;
Node* prev = nullptr;
};
void insertNode(Node* head)
{
Node* newNode = new Node; //直接插入一个元素,这样就不用多次判断head->next是否为NULL了
newNode->next = head->next;
newNode->prev = head;
head->next = newNode;
for (int i = 1; i < 600; i++)
{
Node* newNode = new Node;
newNode->next = head->next;
newNode->prev = head;
head->next->prev = newNode;
head->next = newNode;
}
}
Node* createAList()
{
return new Node;
}
②大数乘法
让程序模仿我们手算的过程即可。
void multiple(Node* source, Node* target, int n)
{//source指乘数,而结果将存在source中
int temp = 0, ret = 0, left = 0; //temp指产生的临时变量,ret指进位,left指留下来的数
while (source)
{
temp = source->data * n + ret;
left = temp % 10;
ret = temp / 10;
target->data = left;
source = source->next;
target = target->next;
}
}
③大数加法
主要用来求这次结果与上次的和,模拟手算。
void add(Node* sum, Node* num)
{
//num为这次计算结果,相加的和存于sum中,依然需要传刚开始的节点
int temp = 0, ret = 0;
while (sum && num)
{
temp = sum->data + num->data + ret;
sum->data = temp % 10;
ret = temp / 10;
sum = sum->next;
num = num->next;
}
}
④大数除法
仍然是模拟手算。
void divison(Node *source, int n)
{
//值得注意的是,此次传入的应是尾节点
int temp = 0, ret = 0;
while (source)
{
int dividend = temp + source->data; //计算过程中的被除数
int now = dividend / n; //这里应该是列式计算时,计算符号上面的数
if (!now)
{
temp = dividend * 10;
}
else
{
temp = (dividend % n) * 10;
}
source->data = now;
source = source->prev;
}
}
⑤开始计算
int main()
{
//必要初始化
Node *sum = createAList();
Node *num = createAList();
insertNode(num);
insertNode(sum);
//获得尾结点
Node *sumTail = sum, *numTail = num;
while (sumTail->next != nullptr)
{
sumTail = sumTail->next;
}
while (numTail->next != nullptr)
{
numTail = numTail->next;
}
//从3开始,简化运算
numTail->data = 3;
sumTail->data = 3;
for (int i = 1; i < 1000; i++)
{
int dividend = (2 * i) * (2 * i + 1) * 4;
int mult = (2 * i - 1) * (2 * i - 1);
//先做除法,否则会溢出
divison(numTail, dividend);
//再做乘法,注意从头结点开始
multiple(num, mult);
//相加
add(sum, num);
}
//指定输出位数输出
int n;
std::cin >> n;
std::cout << sumTail->data;
sumTail = sumTail->prev;
std::cout << ".";
for (int i = 0; i < n - 1; i++)
{
std::cout << sumTail->data;
sumTail = sumTail->prev;
}
}
输出结果:

成功!
完整代码:
#include <iostream>
struct Node
{
int data = 0;
Node *next = nullptr;
Node *prev = nullptr;
};
void insertNode(Node *head)
{
Node *newNode = new Node; //直接插入一个元素,这样就不用多次判断head->next是否为NULL了
newNode->next = head->next;
newNode->prev = head;
head->next = newNode;
for (int i = 1; i < 600; i++)
{
Node *newNode = new Node;
newNode->next = head->next;
newNode->prev = head;
head->next->prev = newNode;
head->next = newNode;
}
}
Node *createAList()
{
return new Node;
}
void multiple(Node *source, int n)
{
int temp = 0, ret = 0; // temp指产生的临时变量,ret指进位,left指留下来的数
while (source)
{
temp = source->data * n + ret;
ret = temp / 10;
source->data = temp % 10;
source = source->next;
}
}
void add(Node *sum, Node *num)
{
// num为这次计算结果,相加的和存于sum中,依然需要传刚开始的节点
int temp = 0, ret = 0;
while (sum && num)
{
temp = sum->data + num->data + ret;
sum->data = temp % 10;
ret = temp / 10;
sum = sum->next;
num = num->next;
}
}
void divison(Node *source, int n)
{
//值得注意的是,此次传入的应都是尾节点
int temp = 0, ret = 0;
while (source)
{
int dividend = temp + source->data; //计算过程中的被除数
int now = dividend / n; //这里应该是列式计算时,计算符号上面的数
if (!now)
{
temp = dividend * 10;
}
else
{
temp = (dividend % n) * 10;
}
source->data = now;
source = source->prev;
}
}
int main()
{
//必要初始化
Node *sum = createAList();
Node *num = createAList();
insertNode(num);
insertNode(sum);
//获得尾结点
Node *sumTail = sum, *numTail = num;
while (sumTail->next != nullptr)
{
sumTail = sumTail->next;
}
while (numTail->next != nullptr)
{
numTail = numTail->next;
}
//从3开始,简化运算
numTail->data = 3;
sumTail->data = 3;
for (int i = 1; i < 1000; i++)
{
int dividend = (2 * i) * (2 * i + 1) * 4;
int mult = (2 * i - 1) * (2 * i - 1);
//先做除法,否则会溢出
divison(numTail, dividend);
//再做乘法,注意从头结点开始
multiple(num, mult);
//相加
add(sum, num);
}
//指定输出位数输出
int n;
std::cin >> n;
std::cout << sumTail->data;
sumTail = sumTail->prev;
std::cout << ".";
for (int i = 0; i < n - 1; i++)
{
std::cout << sumTail->data;
sumTail = sumTail->prev;
}
}
更新:才发现此题是NOJ数据结构实验第二题
如果你一点没变地复制粘贴上去,肯定会WA,因为我输出的不是小数点后几位
如果你输入了n输出的是3.1415,所以你只要把倒数第六行n-1改成n就行了。

浙公网安备 33010602011771号