【问题标题】:Using an iterator in a recursive function results in a segmentation fault在递归函数中使用迭代器会导致分段错误
【发布时间】:2015-01-01 09:26:02
【问题描述】:

我写了一个程序,它接受 N 个代表学生技能水平的整数测试用例,并尝试找到可能的最小组的总数,如果唯一的限制是技能水平不能相等团队并且没有大于1的技能差距。所以下面的测试用例:

4 5 2 3 -4 -3 -5

会输出:

3

因为可能的团队是 {-4,-3,-5} 和 {4,5,2,3},因为第一组只有三个成员,所以输出是 3。

我决定使用链表和递归函数来解决这个问题。一个递归函数会在一个整数的左右寻找一个比它大一个大小的整数,如果找到一个,然后从列表中删除该元素并返回 1。另一个函数寻找一个小于 1 的整数也是如此。这应该导致一个组的总和,我可以比较不同的总和以找到最小的总和。不幸的是,当我尝试实现这一点时,不仅会遇到分段错误,而且经过几次迭代后出现的数字甚至都不是列表的一部分,而且非常大。

#include <cmath>
#include <cstdio>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

int findHigherSkillLevel(int skillLevel, list<int>::iterator *it, list<int> &list) {
  if (it == NULL) return 0;

  if (**it == (skillLevel + 1)) {
    //cout << "test3" << endl;
    skillLevel++;
    list.erase(*it); 
    *it = list.begin();   
    //cout << "Iterator in the higher skill level function if it finds a skill level higher by 1: " << **it << endl;
    //cout << "The skill level is: " << skillLevel << endl;
    return 1 + findHigherSkillLevel(skillLevel, it, list);
  } else {
    //cout << "Iterator in the higher skill level function if it doesn't find one: " << **it << endl;
    return findHigherSkillLevel(skillLevel, ++it, list);
  }

  return 0;
}

int findLowerSkillLevel(int skillLevel, list<int>::iterator *it, list<int> &list) {
  if (it == NULL) return 0;

  if (**it == (skillLevel - 1)) {
    skillLevel--;
    list.erase(*it);
    *it = list.begin();
    return 1 + findLowerSkillLevel(skillLevel, ++it, list);
  } else {
    //cout << "test2" << endl;
    return findLowerSkillLevel(skillLevel, ++it, list);
  }

  return 0;
}

int findGroupsSizes(list<int>::iterator *it, list<int> &list) {
  if (it == NULL) return 0;
  int groupSize = 1;
  int skillLevel = **it;
  *it = list.erase(*it);
  //cout << "Iterator value in the first function: " << **it << endl;
  groupSize += findHigherSkillLevel(skillLevel, it, list) + findLowerSkillLevel(skillLevel, it, list);

  return groupSize;
}

如果我要使用上面提到的测试用例,它会遍历 4、5、2,然后弹出一些奇怪的数字,最后出现 seg 错误。如果您从这些递归的列表中弹出迭代函数,是否不可能在递归函数上使用迭代器?

main() 实际上接受了 t 个测试用例,后跟 t 行 N 个分隔的整数。我使用以下作为测试用例:

4  
7 4 5 2 3 -4 -3 -5  
1 -4  
4 3 2 3 1  
7 1 -2 -3 -4 2 0 -1

如果重要的话,这里是主要的:

int main() {
  int t; // the number of test cases
  cin >> t;
  vector<list<int> > skillLevels(t, list<int>());
  // input for each test case
  for (int i = 0; i < t; i++) {
    int n; // number of students for this test case
    cin >> n;

    // initialize the list for this test case
    for (int j = 0; j < n; j++) {
       int skillLevel;
       cin >> skillLevel;
       skillLevels[i].push_back(skillLevel);
    }
  }

  // recursively scan lists for smallest teams
  for (int i = 0; i < t; i++) {
    int minGroupNumber = skillLevels[i].size();
    list<int>::iterator iterator = skillLevels[i].begin();
    int skillLevel = skillLevels[i].front();

    while (!skillLevels[i].empty()) {
      iterator = skillLevels[i].begin();
      int currentGroupSize = findGroupsSizes(&iterator, skillLevels[i]);
      cout << currentGroupSize << endl; 
      if (currentGroupSize < minGroupNumber)
        minGroupNumber = currentGroupSize;
      //cout << minGroupNumber << endl;
      if (!skillLevels[i].empty()) skillLevels[i].pop_front();
    }
    cout << minGroupNumber << endl;
  }

  return 0;
}

【问题讨论】:

  • erase 返回的迭代器可能超出末尾,如果您删除最后一个元素,但在取消引用之前没有检查。
  • 顺便说一句,你的递归是没有意义的。都是尾递归,可以用一个简单的循环代替。

标签: c++ list recursion iterator segmentation-fault


【解决方案1】:

++it 正在递增指针(使其无效)而不是迭代器。你可能想要++*it

但这也可能使您超出列表的末尾。

【讨论】:

  • 这似乎正在工作,因为它在我打印出来时正确地生成了数字,而且就像你这次提到的那样,它超出了列表。有没有办法有效地确保它不会迭代结束点?我尝试使用 (*it == list.end()) 确保它停止但它似乎继续......
猜你喜欢
  • 1970-01-01
  • 2013-09-21
  • 1970-01-01
  • 2014-10-15
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
  • 2011-11-22
  • 1970-01-01
相关资源
最近更新 更多