我正在编写一个程序来寻找从1,000,000开始的最长的Collatz序列。
我为这段代码感到自豪,它看起来非常高效,干净,写得很好......直到我试着运行它。经过一些调试以使其编译后,我发现当我运行程序时,它会崩溃。
我用过两个
int array[1000000];
和
int *array;
array = (int*)calloc(s, sizeof(int));
(s=1000000
)
声明一个包含1,000,000个空格的数组。
所以我的问题的一部分A):声明这个大小的数组是荒谬的还是可能的?
我的问题的和B部分:这用于各种各样的'清单',检查已经看过哪些数字。是否有一种更简单,更好或者只是不同的“检查”数字的方法,而不是我应该使用的?
代码如下:
// This is a program to find the longest Collatz sequence starting under 1,000,000
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Collatz sequence: IF EVEN n/2 :: IF ODD 3n+1
//define ints
int i;
int n;
int c; // counter of sequence length
int longestsequence = 0;
int beststart;
int s = 1000000; //size of array
//define int array
//int array[999999];
//define array using calloc
//define pointer for calloc int array
int *array;
// do your calloc thing
array = (int*)calloc(s, sizeof(int)); // allocates 1,000,000 spots (s) of size "int" to array "array"
//fill array
for(i = 0; i < 1000000; i++)
{
array[i] = i;
}
for(i = 999999; i > 500000; i--)
{
if(array[i] == 0) // skip if number has already been seen
goto done;
n = i;
c = 0;
//TEST
printf("Current starting number is: %d\n", i);
//TEST
while(n != 4) // run and count collatz sequence
{
//TEST
//printf("test1\n");
//TEST
if(n % 2 == 0) // EVEN
n = n/2;
else // ODD
n = 3 * n + 1;
//TEST
//printf("test2\n");
//TEST
c++;
//TEST
//printf("test3\n");
//TEST
if(n < 1000000 && array[n] != 0) // makes note of used numbers under 1000000
array[n] = 0;
//TEST
//printf("test4\n");
//TEST
}
if(longestsequence < c)
{
longestsequence = c;
beststart = i;
//TEST
printf("Current best start is: %d\n", beststart);
//TEST
}
done:
}
printf("the starting number that produces the longest Collatz sequence is...\n");
printf("%d\n", beststart);
getchar();
return 0;
}
感谢您提供的所有帮助和建议!我们非常感谢有用资源的链接。
UPDATE!
1.我的代码现在看起来像这样^^^^
和
2.程序运行,然后神秘地停在i
值999167
答案 0 :(得分:1)
for(i = 999999; i > 4; i++)
你可以在这里轻松超越数组边界。我想你的意思是
for(i = 999999; i > 4; --i)
// ^^^
此外,与您的实施一样,100万元素是不够的。
以n == 999999
为例。在第一步中,您计算3 * n + 1
,这显然大于1000000.一个简单的解决方案是更改
if(array[n-1] != 0) // makes note of used numbers
array[n-1] = 0;
到
if(n < s && array[n-1] != 0) // makes note of used numbers
array[n-1] = 0;
仅在n
超出数组边界时禁用结果查找。
答案 1 :(得分:1)
您可以使用简单的链接数字列表,这将以“长”搜索时间为代价来降低内存需求。我总是注意到一些重复:
1
2 → 1 (already seen in 1, so link to the existing 1)
3 → 5 → 16 → 8 → 4 → 2 (already seen in 2, so link to the existing 2)
4 (link to existing after 8)
5 (link to existing after 5)
etc.
对于某些数字,您将有一个数字A和可能还有一个数字B链接到数字N,但是N只会链接到一个数字C.例如:
A -> N -> C
3 -> 10 -> 5
20 -> 10 -> 5
B -> N -> C
当然,您可以通过存储列表的长度和包含下一个相邻数字的额外指针来优化它,从而允许您使用该长度作为指导来实现二进制搜索。
但是,如果您只是寻找最长的序列长度而不是序列本身,为什么不只是存储找到的最长长度并将其与当前序列的长度进行比较?存储数字仅用于计算长度似乎有点矫枉过正。类似下面的伪代码:
Longest := 0
For N = 1 To 1000000
Length := 1
X := N
While X != 1
Length := Length + 1
If IsEven(X) Then
X := 3 * X + 1
Else
X := X / 2
End If
End While
If Length > Longest Then
Longest := Length
End If
End For
Print("Longest sequence less than 1000000 is: ", Longest)
答案 2 :(得分:0)
该行
n = 3 * n + 1;
最终将n
的值设置为高于有效索引。最高有效索引为999999
。在访问阵列之前,您必须确保n
小于或等于1000000
:
if(array[n-1] != 0) // makes note of used numbers
array[n-1] = 0;
答案 3 :(得分:0)
您不会在while循环中检查数组索引[n-1]
,以确保它不超过1,000,000的数组范围。例如,在你的第一个循环i = 999,999
中,它使`n = 999999 * 3 + 1 = 2,999,998&#39;。
解决方法是确保n
不超过您的数组大小。