繁体   English   中英

使用向量时的分割错误

[英]Segmentation Fault when using Vectors

我正在尝试从projecteuler.net http://projecteuler.net/problem=14解决问题

这就是问题:

为正整数的集合定义了以下迭代序列:

n→n / 2(n为偶数)n→3n +1(n为奇数)

使用上面的规则并从13开始,我们生成以下序列:

13→40→20→10→5→16→8→4→2→1可以看出,该序列(从13开始并在1结束)包含10个项。 尽管尚未证明(Collat​​z问题),但可以认为所有起始数字都以1结尾。

最长的链条中小于100万的哪个起始数字?

注意:链条启动后,期限就可以超过一百万。

我首先使用了递归解决方案,但是经过大约100,000次迭代后,出现了分段错误。 因此,我提出了一个迭代解决方案,希望能够解决该问题。 在同一点发生分段错误。 我查看了堆栈跟踪,发现将值添加到向量时出现了问题,我在下面标记了这一行。 我认为向量会自动调整大小,因此我对此问题感到非常困惑。 谢谢你的帮助。 这是代码:

#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
 int ITERATIONS=100000;

int main()
{
vector<int> maxArray;
vector<int> newArray;
int max_size = 0;
int n = 2;
int collatz = n;
while(n <= ITERATIONS){

#Stack trace error# 
newArray.push_back(collatz);
#Stack trace error#

if(collatz == 1){
++n;
if(newArray.size() > max_size){
maxArray.clear();
for(vector<int>::const_iterator i = newArray.begin(); i < newArray.end(); ++i){
maxArray.push_back(*i);
}
max_size = newArray.size();
}
newArray.clear();
collatz = n;
}
else if(collatz%2 == 0)
collatz = collatz/2;
else
collatz = 3*collatz+1;
}
for(vector<int>::const_iterator i = maxArray.begin(); i < maxArray.end(); ++i){
cout << *i << " "; 
}
cout << "\n" << max_size;
}

堆栈跟踪:

#0  0x00132416 in __kernel_vsyscall ()
#1  0x002641df in raise () from /lib/i386-linux-gnu/libc.so.6
#2  0x00267825 in abort () from /lib/i386-linux-gnu/libc.so.6 #3  0x001e013d in __gnu_cxx::__verbose_terminate_handler() ()  from /usr/lib/i386-linux-gnu/libstdc++.so.6
#4  0x001dded3 in ?? () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#5  0x001ddf0f in std::terminate() ()  from /usr/lib/i386-linux-gnu/libstdc++.so.6
#6  0x001de05e in __cxa_throw () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#7  0x001de67f in operator new(unsigned int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#8  0x08049362 in __gnu_cxx::new_allocator<int>::allocate (this=0xbffff214, 
__n=536870912) at /usr/include/c++/4.6/ext/new_allocator.h:92
#9  0x0804923c in std::_Vector_base<int, std::allocator<int> >::_M_allocate (
this=0xbffff214, __n=536870912)   at /usr/include/c++/4.6/bits/stl_vector.h:150
#10 0x08048e7f in std::vector<int, std::allocator<int> >::_M_insert_aux (
this=0xbffff214, __position=..., __x=@0xbffff220: -91)
at /usr/include/c++/4.6/bits/vector.tcc:327
#11 0x08048bdd in std::vector<int, std::allocator<int> >::push_back (
this=0xbffff214, __x=@0xbffff220: -91)
at /usr/include/c++/4.6/bits/stl_vector.h:834
#12 0x08048897 in main () at iterativeCollatz.cpp:16

条件i < newArray.end()应该是i != newArray.end() 当然,这也适用于i < maxArray.end()

#6  0x001de05e in __cxa_throw () from /usr/lib/i386-linux-gnu/libstdc++.so.6

__cxa_throw调用表明正在抛出C ++异常。

#5  0x001ddf0f in std::terminate() ()  from /usr/lib/i386-linux-gnu/libstdc++.so.6

std::terminate函数立即退出应用程序。 这可能是由于以下几个原因:

  1. 在对象的析构函数中引发异常,而在引发另一个异常时。
  2. 该程序没有try ... catch处理程序。

在这种情况下,选项2最有可能。 运行该程序应导致类似以下内容:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

Program received signal SIGABRT, Aborted.

这给你的例外(的消息what输出)。

#7  0x001de67f in operator new(unsigned int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6

此行表示分配内存时触发了异常(最有可能是std::bad_alloc ,指示内存不足)。

因此,我将检查您是否没有分配内存不足的大向量。

注意:您可以通过编写类似以下内容来添加自己的try...catch处理程序:

try
{
    // Your code here.
}
catch (const std::exception &e)
{
    std::cout << "Error: " << e.what() << std::endl;
}

每当vector实现不再有空间时, vector实现都会增加它们的大小。 这通常是通过将空间加倍(2、4、8、16,...)来完成的。 这将很快变得非常大,并且您拥有2个向量,可容纳100000个元素。 还要注意,在增加向量时,它需要保留旧数据以将其复制到新向量中。

您可以在maxArraynewArray上使用reserve方法在循环之前设置所需的大小。 那是:

maxArray.reserve(ITERATIONS);
newArray.reserve(ITERATIONS);

由于向量不必增加内部数据数组来添加新元素,因此这也将确保更干净的性能。

我们进行以下观察:

  1. 最小的单个链仅由数字1组成。其长度为1。
  2. 长链只能通过将 x放在以x/2 (如果x为偶数)或3x+1 (如果x为奇数)开头的链上而形成。 长链的长度为1加上尾巴的长度。
  3. 连锁店开始运作后,期限就可以超过一百万。
  4. 解决这个问题实际上并不需要负数。
  5. 没有链长为0。

我们得出以下结论:

  1. 从观察1和2:一旦找到从x开始的链长,就必须记住它。 这避免了重新计算尾巴的长度。 此外,我们可以将链长度解释为0 (这是默认构造std::size ),因为“此长度尚未计算”。
  2. 从观察值3:对于任何x > 1000000 ,如果最终需要计算从x开始的链的长度,则不能保证我们会对从y开始的每个链的长度感兴趣,以使x > y >= 1000000 因此,我们应该使用关联的数据结构(例如std::map ),而不是std::vector来存储记录的长度:
  3. 从观察值3和4:我们将使用尽可能大的无符号整数类型。 在不使用bignum库(例如GMP)的情况下,我们想要的类型是std::uint64_t
  4. 从观察5:我们可以使用链长值为0来表示“此链长尚未计算”。 这特别方便,因为C ++的关联容器在将operator []与容器中不存在的键一起使用时默认构造一个值,并且将整数类型的默认构造值初始化为0。

为了方便起见,使用C ++ 11构造编写的结果程序是这样的:

#include <iostream>
#include <map>
#include <set>
#include <stack>

int main()
{
  typedef std::uint64_t num;

  // ys[x] is the length of the chain starting at x.
  // xms is the set of numbers that yield the longest chains.
  // ym is the length of the longest chain so far.
  std::map<num, num> ys = {{1,1}};
  std::set<num> xms = {1};
  num ym = 1;

  for (num i = 2; i < 1000000; ++i)
  {
    std::stack<num> xs;
    num x = i, y = ys[x];

    // Compute successive chain elements until
    // a base element is reached whose chain
    // length has already been memoized.
    while (!y)
    {
      xs.push(x);
      x = (x & 1) ? (3*x + 1) : (x/2);
      y = ys[x];
    }

    // The lengths of the newly computed elements
    // can be found by repeatedly incrementing
    // the base element's chain length.
    while (!xs.empty())
    {
      x = xs.top();
      ys[x] = ++y;
      xs.pop();
    }

    // Keep track of which number(s)
    // yield the longest chain(s).
    if (y >= ym)
    {
      if (y > ym)
      {
        xms.clear();
        ym = y;
      }
      xms.insert(x);
    }
  }

  for (num xm : xms)
    std::cout << xm << ' ';

  return 0;
}

我已经测试了您的代码,但是没有SIGSEGV,也许您应该提供更多信息。

这是我的建议:

向量类有一个名为capacity()的成员函数,也许您应该检查一下。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM