C 中的fibonacci Memoization算法
Fibonacci memoization algorithm in C++
我在动态编程中有点挣扎。更具体地,实施一种用于查找fibonacci数字n的算法。
我有一种可行的天真算法:
int fib(int n) {
if(n <= 1)
return n;
return fib(n-1) + fib(n-2);
}
但是,当我尝试使用回忆进行操作时,功能总是返回0:
int fib_mem(int n) {
if(lookup_table[n] == NIL) {
if(n <= 1)
lookup_table[n] = n;
else
lookup_table[n] = fib_mem(n-1) + fib_mem(n-2);
}
return lookup_table[n];
}
我已经定义了Lookup_table,最初存储在所有元素中。
有什么想法可能是什么问题?
这是按要求的整个程序:
#include <iostream>
#define NIL -1
#define MAX 100
long int lookup_table[MAX];
using namespace std;
int fib(int n);
int fib_mem(int n);
void initialize() {
for(int i = 0; i < MAX; i++) {
lookup_table[i] == NIL;
}
}
int main() {
int n;
long int fibonnaci, fibonacci_mem;
cin >> n;
// naive solution
fibonnaci = fib(n);
// memoized solution
initialize();
fibonacci_mem = fib_mem(n);
cout << fibonnaci << endl << fibonacci_mem << endl;
return 0;
}
int fib(int n) {
if(n <= 1)
return n;
return fib(n-1) + fib(n-2);
}
int fib_mem(int n) {
if(lookup_table[n] == NIL) {
if(n <= 1)
lookup_table[n] = n;
else
lookup_table[n] = fib_mem(n-1) + fib_mem(n-2);
}
return lookup_table[n];
}
我倾向于通过将幼稚的实现与回忆混合来找到最简单的写作方法:
int fib_mem(int n);
int fib(int n) { return n <= 1 ? n : fib_mem(n-1) + fib_mem(n-2); }
int fib_mem(int n)
{
if (lookup_table[n] == NIL) {
lookup_table[n] = fib(n);
}
return lookup_table[n];
}
#include <iostream>
#define N 100
using namespace std;
const int NIL = -1;
int lookup_table[N];
void init()
{
for(int i=0; i<N; i++)
lookup_table[i] = NIL;
}
int fib_mem(int n) {
if(lookup_table[n] == NIL) {
if(n <= 1)
lookup_table[n] = n;
else
lookup_table[n] = fib_mem(n-1) + fib_mem(n-2);
}
return lookup_table[n];
}
int main()
{
init();
cout<<fib_mem(5);
cout<<fib_mem(7);
}
使用完全相同的函数,这很好。
您在lookup_table
的初始化中做错了什么。
由于问题是初始化,因此C 标准库允许您初始化序列而不必编写for
循环,从而阻止您犯错误,例如使用==
而不是=
。p> std :: fill_n函数这样做:
#include <algorithm>
//...
void initialize()
{
std::fill_n(lookup_table, MAX, NIL);
}
有趣的概念。通过回忆加速。
有一个不同的概念。您可以称其为编译时间纪念。但实际上,这是所有适合64位值的斐波那契数的编译时间预算。
斐波那契序列的一个重要特性是这些值的增长很强。因此,整数数据类型中的所有现有构建都将相当快地溢出。
使用BINET的公式,您可以计算出第93 fibonacci编号是适合64位无签名值的最后一个。
和在编译过程中计算93个值是一个非常简单的任务。
我们将首先定义计算斐波那契号的默认方法为 constexpr
函数:
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) noexcept {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
这样,可以在运行时轻松计算斐波那契数。然后,我们用所有斐波那契号填充std::array
。我们还使用constexpr
,并将其制成带有variadic参数包的模板。
我们使用 std::integer_sequence
创建一个索引fibonacci编号0,1,2,3,4,5,....
straigtforward且不复杂:
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
此功能将用整数序列为0,1,2,3,4,...并返回带有相应fibonacci编号的std::array<unsigned long long, ...>
。
我们知道我们可以存储最大93个值。因此,我们将发出下一个功能,它将用整数序列1,2,3,4,...,92,93称为上述功能,就像这样:
constexpr auto generateArray() noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
现在,最后,
constexpr auto FIB = generateArray();
将为我们提供一个编译时std::array<unsigned long long, 93>
,其中包含所有fibonacci编号的名称fib。而且,如果我们需要fibonacci编号,那么我们可以简单地编写FIB[i]
。运行时不会计算。
我认为没有更快的方法来计算fibonacci编号。
请参阅下面的完整程序:
#include <iostream>
#include <array>
#include <utility>
// ----------------------------------------------------------------------
// All the following will be done during compile time
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
// We will automatically build an array of Fibonacci numberscompile time
// Generate a std::array with n elements
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
// Max index for Fibonaccis that for in an 64bit unsigned value (Binets formula)
constexpr size_t MaxIndexFor64BitValue = 93;
// Generate the required number of elements
constexpr auto generateArray()noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
// This is an constexpr array of all Fibonacci numbers
constexpr auto FIB = generateArray();
// ----------------------------------------------------------------------
// Test
int main() {
// Print all possible Fibonacci numbers
for (size_t i{}; i < MaxIndexFor64BitValue; ++i)
std::cout << i << "t--> " << FIB[i] << 'n';
return 0;
}
通过Microsoft Visual Studio社区2019,版本16.8.2。
开发和测试另外用Clang11.0和GCC10.2
进行了编译和测试。语言:C 17
initialize()
函数中存在错误:
void initialize() {
for(int i = 0; i < MAX; i++) {
lookup_table[i] == NIL; // <- mistake
}
}
在指向的行中,您比较lookup_table[i]
和NIL
(并且不要使用结果),而不是将NIL
分配给lookup_table[i]
。
进行分配,您应该使用=
而不是==
。
此外,在这种情况下,最正确的做法是启用所有警告的程序。例如,MS VC 显示以下警告:
warning C4553: '==': operator has no effect; did you intend '='?
错误是在初始化函数上(您使用了比较操作员'==',其中想要归因运算符'=')。但是,在语义上,您不需要使用-1(nil)初始化look_table,因为斐波那契的结果永远不会为0(零);因此,您可以用零初始化所有内容。在最终解决方案下方看:
#include <iostream>
#define NIL 0
#define MAX 1000
long int lookup_table[MAX] = {};
using namespace std;
long int fib(int n) {
if(n <= 1)
return n;
return fib(n-1) + fib(n-2);
}
long int fib_mem(int n) {
assert(n < MAX);
if(lookup_table[n] == NIL) {
if(n <= 1)
lookup_table[n] = n;
else
lookup_table[n] = fib_mem(n-1) + fib_mem(n-2);
}
return lookup_table[n];
}
int main() {
int n;
long int fibonnaci, fibonacci_mem;
cout << " n = "; cin >> n;
// naive solution
fibonnaci = fib(n);
// memoized solution
// initialize();
fibonacci_mem = fib_mem(n);
cout << fibonnaci << endl << fibonacci_mem << endl;
return 0;
}
在我的解决方案中,我正在使用地图而不是数组来存储备忘录。
#include <iostream>
#include <map>
using namespace std;
map<int, unsigned long long> memo;
unsigned long long fibo(int n) {
if (memo[n]) {
return memo[n];
}
if (n <= 1) {
return n;
}
memo[n] = fibo(n-1) + fibo(n-2);
return memo[n];
}
int main() {
int n;
cin >> n;
cout << "Ans: " << fibo(n);
return 0;
}
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 基于ELO的团队匹配算法
- C++选择排序算法中的逻辑错误
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- C++A*算法并不总是在路径中具有目标节点
- 排序算法c++
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- 算法问题:查找从堆栈中弹出的所有序列
- 下面是排序算法O(n)吗
- KMP算法和LPS表构造的运行时间
- 为什么我的排序算法会更改数组值
- 求最大元素位置的分治算法
- 具有非整数边容量的最大流量的Dinic算法
- 到连接组件算法的问题(递归)
- STL算法函数在多个一维容器上的使用
- 读取最后一行代码算法 - c++ 时出现问题
- 括号更改 O(n) 算法
- std::unordered_map 搜索算法是如何实现的?
- 如何实现高效的算法来计算大型数据集的多个不同值?
- C 中的fibonacci Memoization算法